From da222e098dbb8c87ecc9d107be7fe00fc46c22c5 Mon Sep 17 00:00:00 2001 From: Fabian Morgan Date: Mon, 15 Dec 2025 16:05:09 -0800 Subject: [PATCH 1/2] plumbing and CLI utility to revoke STS token --- .../ozone/shell/s3/RevokeSTSTokenHandler.java | 7 +- .../hadoop/ozone/client/ObjectStore.java | 5 +- .../ozone/client/protocol/ClientProtocol.java | 3 +- .../hadoop/ozone/client/rpc/RpcClient.java | 4 +- .../om/protocol/OzoneManagerProtocol.java | 3 +- ...ManagerProtocolClientSideTranslatorPB.java | 3 +- .../src/main/proto/OmClientProtocol.proto | 1 - .../hadoop/ozone/om/OMMetadataManager.java | 2 +- .../ozone/om/OmMetadataManagerImpl.java | 8 +- .../hadoop/ozone/om/codec/OMDBDefinition.java | 8 +- .../s3/security/S3RevokeSTSTokenRequest.java | 35 +-- .../s3/security/S3RevokeSTSTokenResponse.java | 14 +- .../hadoop/ozone/security/S3SecurityUtil.java | 2 +- .../ozone/om/TestOmMetadataManager.java | 35 +-- .../security/TestS3RevokeSTSTokenRequest.java | 251 +----------------- .../ozone/security/TestS3SecurityUtil.java | 14 +- .../ozone/client/ClientProtocolStub.java | 2 +- 17 files changed, 68 insertions(+), 329 deletions(-) diff --git a/hadoop-ozone/cli-shell/src/main/java/org/apache/hadoop/ozone/shell/s3/RevokeSTSTokenHandler.java b/hadoop-ozone/cli-shell/src/main/java/org/apache/hadoop/ozone/shell/s3/RevokeSTSTokenHandler.java index 2f63d4f2a5ad..c292cff03f0a 100644 --- a/hadoop-ozone/cli-shell/src/main/java/org/apache/hadoop/ozone/shell/s3/RevokeSTSTokenHandler.java +++ b/hadoop-ozone/cli-shell/src/main/java/org/apache/hadoop/ozone/shell/s3/RevokeSTSTokenHandler.java @@ -43,11 +43,6 @@ public class RevokeSTSTokenHandler extends S3Handler { description = "STS temporary access key id (for example, ASIA...)") private String accessKeyId; - @Option(names = "-t", - required = true, - description = "STS session token") - private String sessionToken; - @Option(names = "-y", description = "Continue without interactive user confirmation") private boolean yes; @@ -73,7 +68,7 @@ protected void execute(OzoneClient client, OzoneAddress address) } } - client.getObjectStore().revokeSTSToken(accessKeyId, sessionToken); + client.getObjectStore().revokeSTSToken(accessKeyId); out().println("STS token revoked for accessKeyId '" + accessKeyId + "'."); } } diff --git a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/ObjectStore.java b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/ObjectStore.java index 226ebbfb0349..cdfa4aade373 100644 --- a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/ObjectStore.java +++ b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/ObjectStore.java @@ -769,11 +769,10 @@ public AssumeRoleResponseInfo assumeRole(String roleArn, String roleSessionName, /** * Revokes an STS token. * @param accessKeyId The STS accessKeyId (starting with ASIA...) - * @param sessionToken The STS session token * @throws IOException if an error occurs while revoking the STS token */ - public void revokeSTSToken(String accessKeyId, String sessionToken) throws IOException { - proxy.revokeSTSToken(accessKeyId, sessionToken); + public void revokeSTSToken(String accessKeyId) throws IOException { + proxy.revokeSTSToken(accessKeyId); } /** diff --git a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/protocol/ClientProtocol.java b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/protocol/ClientProtocol.java index 0067407aff33..bf8628ca1595 100644 --- a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/protocol/ClientProtocol.java +++ b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/protocol/ClientProtocol.java @@ -1376,8 +1376,7 @@ AssumeRoleResponseInfo assumeRole(String roleArn, String roleSessionName, int du /** * Revokes an STS token. * @param accessKeyId The STS accessKeyId (starting with ASIA...) - * @param sessionToken The STS session token * @throws IOException if an error occurs while revoking the STS token */ - void revokeSTSToken(String accessKeyId, String sessionToken) throws IOException; + void revokeSTSToken(String accessKeyId) throws IOException; } diff --git a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java index 791a159f01be..c6bf3f0e17c5 100644 --- a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java +++ b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/rpc/RpcClient.java @@ -2798,8 +2798,8 @@ public AssumeRoleResponseInfo assumeRole(String roleArn, String roleSessionName, } @Override - public void revokeSTSToken(String accessKeyId, String sessionToken) throws IOException { - ozoneManagerClient.revokeSTSToken(accessKeyId, sessionToken); + public void revokeSTSToken(String accessKeyId) throws IOException { + ozoneManagerClient.revokeSTSToken(accessKeyId); } private static ExecutorService createThreadPoolExecutor( diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java index f98196d7276e..eb6765aee285 100644 --- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/OzoneManagerProtocol.java @@ -1195,10 +1195,9 @@ default AssumeRoleResponseInfo assumeRole(String roleArn, String roleSessionName /** * Revokes an STS token. * @param accessKeyId The STS accessKeyId (starting with ASIA...) - * @param sessionToken The STS session token * @throws IOException if an error occurs while revoking the STS token */ - default void revokeSTSToken(String accessKeyId, String sessionToken) throws IOException { + default void revokeSTSToken(String accessKeyId) throws IOException { throw new UnsupportedOperationException("OzoneManager does not require this to be implemented"); } } diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java index 105d353a4637..3c016419ea40 100644 --- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocolPB/OzoneManagerProtocolClientSideTranslatorPB.java @@ -2676,11 +2676,10 @@ public AssumeRoleResponseInfo assumeRole(String roleArn, String roleSessionName, } @Override - public void revokeSTSToken(String accessKeyId, String sessionToken) throws IOException { + public void revokeSTSToken(String accessKeyId) throws IOException { final OzoneManagerProtocolProtos.RevokeSTSTokenRequest request = OzoneManagerProtocolProtos.RevokeSTSTokenRequest.newBuilder() .setAccessKeyId(accessKeyId) - .setSessionToken(sessionToken) .build(); final OMRequest omRequest = createOMRequest(Type.RevokeSTSToken) diff --git a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto index b24aff586cea..07b895357862 100644 --- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto +++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto @@ -2388,7 +2388,6 @@ message AssumeRoleResponse { message RevokeSTSTokenRequest { required string accessKeyId = 1; - required string sessionToken = 2; } message RevokeSTSTokenResponse { diff --git a/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/OMMetadataManager.java b/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/OMMetadataManager.java index 7afe2c6249a9..82e04b3ff10e 100644 --- a/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/OMMetadataManager.java +++ b/hadoop-ozone/interface-storage/src/main/java/org/apache/hadoop/ozone/om/OMMetadataManager.java @@ -489,7 +489,7 @@ String getMultipartKeyFSO(String volume, String bucket, String key, String * * @return Table. */ - Table getS3RevokedStsTokenTable(); + Table getS3RevokedStsTokenTable(); /** diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java index 3439e04c0636..9d8915dd7dba 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OmMetadataManagerImpl.java @@ -181,7 +181,7 @@ public class OmMetadataManagerImpl implements OMMetadataManager, private TypedTable snapshotRenamedTable; private TypedTable compactionLogTable; - private TypedTable s3RevokedStsTokenTable; + private TypedTable s3RevokedStsTokenTable; private OzoneManager ozoneManager; @@ -489,8 +489,8 @@ protected void initializeOmTables(CacheType cacheType, compactionLogTable = initializer.get(OMDBDefinition.COMPACTION_LOG_TABLE_DEF); - // temporaryAccessKeyId -> sessionToken - // FULL_CACHE keeps revocations in memory as there are not expected to be many revoked tokens + // temporaryAccessKeyId -> insertionTimeMillis + // FULL_CACHE keeps revocations in memory as there are not expected to be many s3RevokedStsTokenTable = initializer.get( OMDBDefinition.S3_REVOKED_STS_TOKEN_TABLE_DEF, CacheType.FULL_CACHE); } @@ -1691,7 +1691,7 @@ public Table getCompactionLogTable() { } @Override - public Table getS3RevokedStsTokenTable() { + public Table getS3RevokedStsTokenTable() { return s3RevokedStsTokenTable; } diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/OMDBDefinition.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/OMDBDefinition.java index 8b4632ef45bf..19da024d7df8 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/OMDBDefinition.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/codec/OMDBDefinition.java @@ -56,7 +56,7 @@ * | userTable | /user :- UserVolumeInfo | * | dTokenTable | OzoneTokenID :- renew_time | * | s3SecretTable | s3g_access_key_id :- s3Secret | - * | s3RevokedStsTokenTable | sts_access_key_id :- sessionToken | + * | s3RevokedStsTokenTable | sts_access_key_id :- insertionTimeMillis | * |------------------------------------------------------------------------| * } * @@ -163,11 +163,11 @@ public final class OMDBDefinition extends DBDefinition.WithMap { S3SecretValue.getCodec()); public static final String S3_REVOKED_STS_TOKEN_TABLE = "s3RevokedStsTokenTable"; - /** s3RevokedStsTokenTable: sts_access_key_id :- sessionToken.*/ - public static final DBColumnFamilyDefinition S3_REVOKED_STS_TOKEN_TABLE_DEF + /** s3RevokedStsTokenTable: sts_access_key_id :- insertionTimeMillis.*/ + public static final DBColumnFamilyDefinition S3_REVOKED_STS_TOKEN_TABLE_DEF = new DBColumnFamilyDefinition<>(S3_REVOKED_STS_TOKEN_TABLE, StringCodec.get(), - StringCodec.get()); + LongCodec.get()); //--------------------------------------------------------------------------- // Volume, Bucket, Prefix and Transaction Tables: 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 ff7a3831d0d6..2f926f26d81a 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 @@ -18,8 +18,6 @@ package org.apache.hadoop.ozone.om.request.s3.security; import java.io.IOException; -import java.time.Clock; -import java.time.ZoneOffset; import java.util.HashMap; import java.util.Map; import org.apache.hadoop.ozone.OzoneConsts; @@ -34,8 +32,6 @@ import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse; -import org.apache.hadoop.ozone.security.STSSecurityUtil; -import org.apache.hadoop.ozone.security.STSTokenIdentifier; import org.apache.hadoop.security.UserGroupInformation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -51,9 +47,6 @@ public class S3RevokeSTSTokenRequest extends OMClientRequest { private static final Logger LOG = LoggerFactory.getLogger(S3RevokeSTSTokenRequest.class); - private static final Clock CLOCK = Clock.system(ZoneOffset.UTC); - - private String originalAccessKeyId; public S3RevokeSTSTokenRequest(OMRequest omRequest) { super(omRequest); @@ -64,27 +57,12 @@ public OMRequest preExecute(OzoneManager ozoneManager) throws IOException { final OzoneManagerProtocolProtos.RevokeSTSTokenRequest revokeReq = getOmRequest().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 - // operations (get/set/revoke). Only the owner of the original access - // key (or an S3 / tenant admin) is allowed to revoke its temporary - // STS credentials. - final String sessionToken = revokeReq.getSessionToken(); - final String tempAccessKeyId = revokeReq.getAccessKeyId(); - final STSTokenIdentifier stsTokenIdentifier = STSSecurityUtil.constructValidateAndDecryptSTSToken( - sessionToken, ozoneManager.getSecretKeyClient(), CLOCK); - originalAccessKeyId = stsTokenIdentifier.getOriginalAccessKeyId(); - - // Validate that the Access Key ID in the request matches the one in the token - // to prevent users from revoking arbitrary keys using a valid token. - if (!stsTokenIdentifier.getTempAccessKeyId().equals(tempAccessKeyId)) { - throw new OMException("Access Key ID in request does not match the session token", - OMException.ResultCodes.INVALID_REQUEST); + // Only S3/Ozone admins can revoke STS tokens by temporary access key ID. + final UserGroupInformation ugi = S3SecretRequestHelper.getOrCreateUgi(getUserInfo().getUserName()); + if (!ozoneManager.isS3Admin(ugi)) { + throw new OMException("Only S3/Ozone admins can revoke STS tokens.", OMException.ResultCodes.PERMISSION_DENIED); } - final UserGroupInformation ugi = S3SecretRequestHelper.getOrCreateUgi(originalAccessKeyId); - S3SecretRequestHelper.checkAccessIdSecretOpPermission(ozoneManager, ugi, originalAccessKeyId); - final OMRequest.Builder omRequest = OMRequest.newBuilder() .setRevokeSTSTokenRequest(revokeReq) .setCmdType(getOmRequest().getCmdType()) @@ -104,15 +82,14 @@ public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, Execut final OzoneManagerProtocolProtos.RevokeSTSTokenRequest revokeReq = getOmRequest().getRevokeSTSTokenRequest(); final String accessKeyId = revokeReq.getAccessKeyId(); - final String sessionToken = revokeReq.getSessionToken(); // All actual DB mutations are done in the response's addToDBBatch(). final OMClientResponse omClientResponse = new S3RevokeSTSTokenResponse( - accessKeyId, sessionToken, omResponse.build()); + accessKeyId, omResponse.build()); // Audit log final Map auditMap = new HashMap<>(); - auditMap.put(OzoneConsts.S3_REVOKESTSTOKEN_USER, originalAccessKeyId); + auditMap.put(OzoneConsts.S3_REVOKESTSTOKEN_USER, getOmRequest().getUserInfo().getUserName()); markForAudit(ozoneManager.getAuditLogger(), buildAuditMessage( OMAction.REVOKE_STS_TOKEN, auditMap, null, getOmRequest().getUserInfo())); diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/security/S3RevokeSTSTokenResponse.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/security/S3RevokeSTSTokenResponse.java index 523311bbadb8..5906cce63aa0 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/security/S3RevokeSTSTokenResponse.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/security/S3RevokeSTSTokenResponse.java @@ -22,6 +22,8 @@ import jakarta.annotation.Nonnull; import java.io.IOException; +import java.time.Clock; +import java.time.ZoneOffset; import org.apache.hadoop.hdds.utils.db.BatchOperation; import org.apache.hadoop.hdds.utils.db.Table; import org.apache.hadoop.ozone.om.OMMetadataManager; @@ -35,22 +37,22 @@ @CleanupTableInfo(cleanupTables = {S3_REVOKED_STS_TOKEN_TABLE}) public class S3RevokeSTSTokenResponse extends OMClientResponse { + private static final Clock CLOCK = Clock.system(ZoneOffset.UTC); + private final String accessKeyId; - private final String sessionToken; - public S3RevokeSTSTokenResponse(String accessKeyId, String sessionToken, @Nonnull OMResponse omResponse) { + public S3RevokeSTSTokenResponse(String accessKeyId, @Nonnull OMResponse omResponse) { super(omResponse); this.accessKeyId = accessKeyId; - this.sessionToken = sessionToken; } @Override public void addToDBBatch(OMMetadataManager omMetadataManager, BatchOperation batchOperation) throws IOException { if (accessKeyId != null && getOMResponse().hasStatus() && getOMResponse().getStatus() == OK) { - final Table table = omMetadataManager.getS3RevokedStsTokenTable(); + final Table table = omMetadataManager.getS3RevokedStsTokenTable(); if (table != null) { - // Store sessionToken as value - table.putWithBatch(batchOperation, accessKeyId, sessionToken); + // Store insertionTimeMillis as value + table.putWithBatch(batchOperation, accessKeyId, CLOCK.millis()); } } } diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/S3SecurityUtil.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/S3SecurityUtil.java index aeb4a2e189a3..2ed41ab3e7ec 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/S3SecurityUtil.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/S3SecurityUtil.java @@ -152,7 +152,7 @@ private static boolean isRevokedStsTempAccessKeyId(STSTokenIdentifier stsTokenId throw new OMException(msg, INTERNAL_ERROR); } - final Table revokedStsTokenTable = metadataManager.getS3RevokedStsTokenTable(); + final Table revokedStsTokenTable = metadataManager.getS3RevokedStsTokenTable(); if (revokedStsTokenTable == null) { final String msg = "Could not determine STS revocation: revokedStsTokenTable is null"; LOG.warn(msg); diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmMetadataManager.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmMetadataManager.java index 3541d303b246..2594e320814b 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmMetadataManager.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/TestOmMetadataManager.java @@ -79,7 +79,7 @@ import org.apache.hadoop.hdds.protocol.StorageType; import org.apache.hadoop.hdds.protocol.proto.HddsProtos; import org.apache.hadoop.hdds.utils.TransactionInfo; -import org.apache.hadoop.hdds.utils.db.Table; +import org.apache.hadoop.hdds.utils.db.TypedTable; import org.apache.hadoop.hdds.utils.db.cache.CacheKey; import org.apache.hadoop.hdds.utils.db.cache.CacheValue; import org.apache.hadoop.ozone.om.codec.OMDBDefinition; @@ -105,6 +105,7 @@ import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PartKeyInfo; import org.apache.hadoop.ozone.snapshot.ListSnapshotResponse; import org.apache.hadoop.util.Time; +import org.apache.ozone.test.TestClock; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.io.TempDir; @@ -1299,34 +1300,36 @@ public void testS3RevokedStsTokenTablePutAndGet() throws Exception { // Ensure the table is initialized assertNotNull(omMetadataManager.getS3RevokedStsTokenTable(), "s3RevokedStsTokenTable should be initialized"); + final TestClock clock = TestClock.newInstance(); final String tempAccessKeyId1 = "ASIA7VUS1EOBCW8RRJVR"; - final String sessionToken1 = "test-session-token-1"; + final long insertionTime1 = clock.millis(); final String tempAccessKeyId2 = "ASIA904E65QIGL9ON305"; - final String sessionToken2 = "test-session-token-2"; - - final Table table = omMetadataManager.getS3RevokedStsTokenTable(); + final long insertionTime2 = insertionTime1 + 1234L; // This table is configured as FULL_CACHE in OmMetadataManagerImpl. // A put() writes to RocksDB but does not update the table cache, so get() and getIfExist() will return null unless // the cache is updated with addCacheEntry(). getSkipCache() will read the DB instead of the cache. - table.put(tempAccessKeyId1, sessionToken1); - table.put(tempAccessKeyId2, sessionToken2); + final TypedTable revokedTable = + (TypedTable) omMetadataManager.getS3RevokedStsTokenTable(); + + revokedTable.put(tempAccessKeyId1, insertionTime1); + revokedTable.put(tempAccessKeyId2, insertionTime2); // Verify the values are persisted in RocksDB. - assertEquals(sessionToken1, table.getSkipCache(tempAccessKeyId1)); - assertEquals(sessionToken2, table.getSkipCache(tempAccessKeyId2)); + assertEquals(insertionTime1, revokedTable.getSkipCache(tempAccessKeyId1)); + assertEquals(insertionTime2, revokedTable.getSkipCache(tempAccessKeyId2)); // Update cache to make get/getIfExist reflect the write for FULL_CACHE tables. - table.addCacheEntry(tempAccessKeyId1, sessionToken1, 1L); - table.addCacheEntry(tempAccessKeyId2, sessionToken2, 1L); + revokedTable.addCacheEntry(tempAccessKeyId1, insertionTime1, 1L); + revokedTable.addCacheEntry(tempAccessKeyId2, insertionTime2, 1L); // Verify get and getIfExist return the stored value - assertEquals(sessionToken1, table.get(tempAccessKeyId1)); - assertEquals(sessionToken1, table.getIfExist(tempAccessKeyId1)); - assertEquals(sessionToken2, table.get(tempAccessKeyId2)); - assertEquals(sessionToken2, table.getIfExist(tempAccessKeyId2)); + assertEquals(insertionTime1, revokedTable.get(tempAccessKeyId1)); + assertEquals(insertionTime1, revokedTable.getIfExist(tempAccessKeyId1)); + assertEquals(insertionTime2, revokedTable.get(tempAccessKeyId2)); + assertEquals(insertionTime2, revokedTable.getIfExist(tempAccessKeyId2)); // Unknown key should return null for getIfExist - assertNull(table.getIfExist("ASIA_UNKNOWN_ACCESS_KEY")); + assertNull(revokedTable.getIfExist("ASIA_UNKNOWN_ACCESS_KEY")); } } diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3RevokeSTSTokenRequest.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3RevokeSTSTokenRequest.java index 9a68c047f008..cba31fa82dd6 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3RevokeSTSTokenRequest.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3RevokeSTSTokenRequest.java @@ -17,33 +17,23 @@ package org.apache.hadoop.ozone.om.request.s3.security; -import static org.apache.hadoop.security.authentication.util.KerberosName.DEFAULT_MECHANISM; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertThrows; import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; -import java.io.IOException; -import java.util.Optional; import java.util.UUID; -import org.apache.hadoop.hdds.security.symmetric.SecretKeyClient; import org.apache.hadoop.ipc.ExternalCall; import org.apache.hadoop.ipc.Server; -import org.apache.hadoop.ozone.om.OMMultiTenantManager; import org.apache.hadoop.ozone.om.OzoneManager; import org.apache.hadoop.ozone.om.exceptions.OMException; import org.apache.hadoop.ozone.om.request.OMClientRequest; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type; -import org.apache.hadoop.ozone.security.STSTokenSecretManager; -import org.apache.hadoop.ozone.security.SecretKeyTestClient; import org.apache.hadoop.security.UserGroupInformation; -import org.apache.hadoop.security.authentication.util.KerberosName; -import org.apache.ozone.test.TestClock; import org.junit.jupiter.api.AfterEach; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; /** @@ -51,55 +41,26 @@ */ public class TestS3RevokeSTSTokenRequest { - private static final TestClock CLOCK = TestClock.newInstance(); - - private STSTokenSecretManager stsTokenSecretManager; - private SecretKeyClient secretKeyClient; - private OMMultiTenantManager omMultiTenantManager; - - @BeforeEach - public void setUp() throws Exception { - // Initialize KerberosName rules so that UGI short names derived from - // principals like "alice@EXAMPLE.COM" are computed correctly. - KerberosName.setRuleMechanism(DEFAULT_MECHANISM); - KerberosName.setRules( - "RULE:[2:$1@$0](.*@EXAMPLE.COM)s/@.*//\n" + "RULE:[1:$1@$0](.*@EXAMPLE.COM)s/@.*//\n" + "DEFAULT"); - - secretKeyClient = new SecretKeyTestClient(); - stsTokenSecretManager = new STSTokenSecretManager(secretKeyClient); - // Multi-tenant manager mock used for tests that exercise the S3 multi-tenancy permission branch. - omMultiTenantManager = mock(OMMultiTenantManager.class); - } - @AfterEach public void tearDown() { Server.getCurCall().remove(); } @Test - public void testPreExecuteFailsForNonOwnerOfOriginalAccessKey() throws Exception { - // Verify that preExecute enforces permissions based on the original access key id encoded in the STS token - // and rejects revocation attempts from non-owners. + public void testPreExecuteFailsForNonAdmin() throws Exception { + // Verify that preExecute rejects non-admin users. final String tempAccessKeyId = "ASIA12345678"; - final String originalAccessKeyId = "original-access-key-id"; - final String sessionToken = createSessionToken(tempAccessKeyId, originalAccessKeyId); + final UserGroupInformation nonAdminUgi = UserGroupInformation.createRemoteUser("non-admin-user"); + Server.getCurCall().set(new StubCall(nonAdminUgi)); - // An RPC call running another Kerberos identity should NOT be allowed to revoke the token whose original - // access key id is different. - final UserGroupInformation tempUgi = UserGroupInformation.createRemoteUser("another-kerberos-identity"); - Server.getCurCall().set(new StubCall(tempUgi)); - - OMException ex; + final OMException ex; try (OzoneManager ozoneManager = mock(OzoneManager.class)) { - when(ozoneManager.isS3MultiTenancyEnabled()).thenReturn(false); when(ozoneManager.isS3Admin(any(UserGroupInformation.class))) .thenReturn(false); - when(ozoneManager.getSecretKeyClient()).thenReturn(secretKeyClient); final OzoneManagerProtocolProtos.RevokeSTSTokenRequest revokeRequest = OzoneManagerProtocolProtos.RevokeSTSTokenRequest.newBuilder() .setAccessKeyId(tempAccessKeyId) - .setSessionToken(sessionToken) .build(); final OMRequest omRequest = OMRequest.newBuilder() @@ -112,120 +73,23 @@ public void testPreExecuteFailsForNonOwnerOfOriginalAccessKey() throws Exception ex = assertThrows(OMException.class, () -> omClientRequest.preExecute(ozoneManager)); } - assertEquals(OMException.ResultCodes.USER_MISMATCH, ex.getResult()); + assertEquals(OMException.ResultCodes.PERMISSION_DENIED, ex.getResult()); } @Test - public void testPreExecuteSucceedsForOriginalAccessKeyOwner() throws Exception { - // Verify that preExecute allows the owner of the original access key id (as encoded in the STS token) - // to revoke the temporary credentials. + public void testPreExecuteSucceedsForAdmin() throws Exception { + // Verify that preExecute allows S3/Ozone admins to revoke STS tokens. final String tempAccessKeyId = "ASIA4567891230"; - final String originalAccessKeyId = "original-access-key-id"; - final String sessionToken = createSessionToken(tempAccessKeyId, originalAccessKeyId); - - // Simulate RPC call running as originalAccessKeyId - final UserGroupInformation originalUgi = UserGroupInformation.createRemoteUser(originalAccessKeyId); - Server.getCurCall().set(new StubCall(originalUgi)); + final UserGroupInformation adminUgi = UserGroupInformation.createRemoteUser("admin-user"); + Server.getCurCall().set(new StubCall(adminUgi)); final OzoneManager ozoneManager = mock(OzoneManager.class); - when(ozoneManager.isS3MultiTenancyEnabled()).thenReturn(false); when(ozoneManager.isS3Admin(any(UserGroupInformation.class))) - .thenReturn(false); - when(ozoneManager.getSecretKeyClient()).thenReturn(secretKeyClient); - - final OzoneManagerProtocolProtos.RevokeSTSTokenRequest revokeRequest = - OzoneManagerProtocolProtos.RevokeSTSTokenRequest.newBuilder() - .setAccessKeyId(tempAccessKeyId) - .setSessionToken(sessionToken) - .build(); - - final OMRequest omRequest = OMRequest.newBuilder() - .setClientId(UUID.randomUUID().toString()) - .setCmdType(Type.RevokeSTSToken) - .setRevokeSTSTokenRequest(revokeRequest) - .build(); - - final OMClientRequest omClientRequest = new S3RevokeSTSTokenRequest(omRequest); - final OMRequest result = omClientRequest.preExecute(ozoneManager); - assertEquals(Type.RevokeSTSToken, result.getCmdType()); - } - - @Test - public void testPreExecuteSucceedsForTenantAccessIdOwner() throws Exception { - // When S3 multi-tenancy is enabled and the original access key id is assigned to a tenant, verify that - // the tenant access ID owner is allowed to revoke the temporary credentials. - final String tenantId = "finance"; - final String originalAccessKeyId = "alice@EXAMPLE.COM"; - final String tempAccessKeyId = "ASIA123456789"; - final String sessionToken = createSessionToken(tempAccessKeyId, originalAccessKeyId); - - // Caller short name "alice" should match the owner username returned from the multi-tenant manager. - final UserGroupInformation callerUgi = UserGroupInformation.createRemoteUser(originalAccessKeyId); - Server.getCurCall().set(new StubCall(callerUgi)); - - final OzoneManager ozoneManager = mock(OzoneManager.class); - when(ozoneManager.isS3MultiTenancyEnabled()).thenReturn(true); - when(ozoneManager.getMultiTenantManager()).thenReturn(omMultiTenantManager); - when(ozoneManager.getSecretKeyClient()).thenReturn(secretKeyClient); - - // Original access key id is assigned to a tenant and owned by "alice". - when(omMultiTenantManager.getTenantForAccessID(originalAccessKeyId)) - .thenReturn(Optional.of(tenantId)); - when(omMultiTenantManager.getUserNameGivenAccessId(originalAccessKeyId)) - .thenReturn("alice"); - // Not a tenant admin; ownership should be sufficient. - when(omMultiTenantManager.isTenantAdmin(callerUgi, tenantId, false)) - .thenReturn(false); - - final OzoneManagerProtocolProtos.RevokeSTSTokenRequest revokeRequest = - OzoneManagerProtocolProtos.RevokeSTSTokenRequest.newBuilder() - .setAccessKeyId(tempAccessKeyId) - .setSessionToken(sessionToken) - .build(); - - final OMRequest omRequest = OMRequest.newBuilder() - .setClientId(UUID.randomUUID().toString()) - .setCmdType(Type.RevokeSTSToken) - .setRevokeSTSTokenRequest(revokeRequest) - .build(); - - final OMClientRequest omClientRequest = new S3RevokeSTSTokenRequest(omRequest); - - final OMRequest result = omClientRequest.preExecute(ozoneManager); - assertEquals(Type.RevokeSTSToken, result.getCmdType()); - } - - @Test - public void testPreExecuteSucceedsForTenantAdmin() throws Exception { - // When S3 multi-tenancy is enabled and the original access key id is assigned to a tenant, verify that a - // tenant admin (who is not the owner) is allowed to revoke the temporary credentials. - final String tenantId = "finance"; - final String originalAccessKeyId = "alice@EXAMPLE.COM"; - final String tempAccessKeyId = "ASIA4567890123"; - final String sessionToken = createSessionToken(tempAccessKeyId, originalAccessKeyId); - - // Caller short name "bob" does not own the access ID but will be configured as tenant admin. - final UserGroupInformation callerUgi = UserGroupInformation.createRemoteUser("bob@EXAMPLE.COM"); - Server.getCurCall().set(new StubCall(callerUgi)); - - final OzoneManager ozoneManager = mock(OzoneManager.class); - when(ozoneManager.isS3MultiTenancyEnabled()).thenReturn(true); - when(ozoneManager.getMultiTenantManager()).thenReturn(omMultiTenantManager); - when(ozoneManager.getSecretKeyClient()).thenReturn(secretKeyClient); - - // Original access key id is assigned to a tenant and owned by "alice". - when(omMultiTenantManager.getTenantForAccessID(originalAccessKeyId)) - .thenReturn(Optional.of(tenantId)); - when(omMultiTenantManager.getUserNameGivenAccessId(originalAccessKeyId)) - .thenReturn("alice"); - // Caller is configured as tenant admin so the check should pass. - when(omMultiTenantManager.isTenantAdmin(callerUgi, tenantId, false)) .thenReturn(true); final OzoneManagerProtocolProtos.RevokeSTSTokenRequest revokeRequest = OzoneManagerProtocolProtos.RevokeSTSTokenRequest.newBuilder() .setAccessKeyId(tempAccessKeyId) - .setSessionToken(sessionToken) .build(); final OMRequest omRequest = OMRequest.newBuilder() @@ -235,99 +99,10 @@ public void testPreExecuteSucceedsForTenantAdmin() throws Exception { .build(); final OMClientRequest omClientRequest = new S3RevokeSTSTokenRequest(omRequest); - final OMRequest result = omClientRequest.preExecute(ozoneManager); assertEquals(Type.RevokeSTSToken, result.getCmdType()); } - @Test - public void testPreExecuteFailsForNonOwnerNonAdminInTenant() throws Exception { - // When S3 multi-tenancy is enabled and the original access key id is assigned to a tenant, verify that a - // non-owner, non-admin caller is rejected. - final String tenantId = "finance"; - final String originalAccessKeyId = "alice@EXAMPLE.COM"; - final String tempAccessKeyId = "ASIA123456789"; - final String sessionToken = createSessionToken(tempAccessKeyId, originalAccessKeyId); - - // Caller short name "carol" does not own the access ID and is not - // configured as tenant admin. - final UserGroupInformation callerUgi = UserGroupInformation.createRemoteUser("carol@EXAMPLE.COM"); - Server.getCurCall().set(new StubCall(callerUgi)); - - final OMException ex; - try (OzoneManager ozoneManager = mock(OzoneManager.class)) { - when(ozoneManager.isS3MultiTenancyEnabled()).thenReturn(true); - when(ozoneManager.getMultiTenantManager()).thenReturn(omMultiTenantManager); - when(ozoneManager.getSecretKeyClient()).thenReturn(secretKeyClient); - - // Original access key id is assigned to a tenant and owned by "alice". - when(omMultiTenantManager.getTenantForAccessID(originalAccessKeyId)) - .thenReturn(Optional.of(tenantId)); - when(omMultiTenantManager.getUserNameGivenAccessId(originalAccessKeyId)) - .thenReturn("alice"); - // Caller is not a tenant admin. - when(omMultiTenantManager.isTenantAdmin(callerUgi, tenantId, false)) - .thenReturn(false); - - final OzoneManagerProtocolProtos.RevokeSTSTokenRequest revokeRequest = - OzoneManagerProtocolProtos.RevokeSTSTokenRequest.newBuilder() - .setAccessKeyId(tempAccessKeyId) - .setSessionToken(sessionToken) - .build(); - - final OMRequest omRequest = OMRequest.newBuilder() - .setClientId(UUID.randomUUID().toString()) - .setCmdType(Type.RevokeSTSToken) - .setRevokeSTSTokenRequest(revokeRequest) - .build(); - - final OMClientRequest omClientRequest = new S3RevokeSTSTokenRequest(omRequest); - - ex = assertThrows(OMException.class, () -> omClientRequest.preExecute(ozoneManager)); - } - assertEquals(OMException.ResultCodes.USER_MISMATCH, ex.getResult()); - } - - @Test - public void testPreExecuteFailsForMismatchedAccessKeyId() throws Exception { - // Verify that if the request access key id does not match the one inside the session token, the request is - // rejected. This prevents a user with a valid session token from revoking arbitrary STS credentials. - final String tempAccessKeyId = "ASIA123456789"; - final String otherAccessKeyId = "ASI987654321"; - final String originalAccessKeyId = "original-access-key-id"; - final String sessionToken = createSessionToken(tempAccessKeyId, originalAccessKeyId); - - // Caller is the owner of the session token, so permissions should pass - final UserGroupInformation originalUgi = UserGroupInformation.createRemoteUser(originalAccessKeyId); - Server.getCurCall().set(new StubCall(originalUgi)); - - final OMException ex; - try (OzoneManager ozoneManager = mock(OzoneManager.class)) { - when(ozoneManager.isS3MultiTenancyEnabled()).thenReturn(false); - when(ozoneManager.isS3Admin(any(UserGroupInformation.class))) - .thenReturn(false); - when(ozoneManager.getSecretKeyClient()).thenReturn(secretKeyClient); - - // Request tries to revoke otherAccessKeyId using a token for tempAccessKeyId - final OzoneManagerProtocolProtos.RevokeSTSTokenRequest revokeRequest = - OzoneManagerProtocolProtos.RevokeSTSTokenRequest.newBuilder() - .setAccessKeyId(otherAccessKeyId) - .setSessionToken(sessionToken) - .build(); - - final OMRequest omRequest = OMRequest.newBuilder() - .setClientId(UUID.randomUUID().toString()) - .setCmdType(Type.RevokeSTSToken) - .setRevokeSTSTokenRequest(revokeRequest) - .build(); - - final OMClientRequest omClientRequest = new S3RevokeSTSTokenRequest(omRequest); - - ex = assertThrows(OMException.class, () -> omClientRequest.preExecute(ozoneManager)); - } - assertEquals(OMException.ResultCodes.INVALID_REQUEST, ex.getResult()); - } - /** * Stub used to inject a remote user into the ProtobufRpcEngine.Server.getRemoteUser() thread-local. */ @@ -344,10 +119,4 @@ public UserGroupInformation getRemoteUser() { return ugi; } } - - private String createSessionToken(String tempAccessKeyId, String originalAccessKeyId) throws IOException { - return stsTokenSecretManager.createSTSTokenString( - tempAccessKeyId, originalAccessKeyId, "arn:aws:iam::123456789012:role/test-role", 3600, - "test-secret-access-key", "test-session-policy", CLOCK); - } } diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/TestS3SecurityUtil.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/TestS3SecurityUtil.java index c5cce385071b..120fe6553198 100644 --- a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/TestS3SecurityUtil.java +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/TestS3SecurityUtil.java @@ -65,7 +65,7 @@ public void testValidateS3CredentialFailsWhenTokenRevoked() throws Exception { // If the revoked STS token table contains an entry for the temporary access key id extracted from the session // token, validateS3Credential should reject the request with REVOKED_TOKEN final OMMetadataManager metadataManager = mock(OMMetadataManager.class); - final Table revokedSTSTokenTable = new InMemoryTestTable<>(); + final Table revokedSTSTokenTable = new InMemoryTestTable<>(); validateS3CredentialHelper( "session-token-a", metadataManager, revokedSTSTokenTable, true, createSTSTokenIdentifier(), REVOKED_TOKEN, "STS token has been revoked"); @@ -83,7 +83,7 @@ public void testValidateS3CredentialWhenMetadataUnavailable() throws Exception { public void testValidateS3CredentialSuccessWhenNotRevoked() throws Exception { // Normal case: token is NOT revoked and request is accepted final OMMetadataManager metadataManager = mock(OMMetadataManager.class); - final Table revokedSTSTokenTable = new InMemoryTestTable<>(); + final Table revokedSTSTokenTable = new InMemoryTestTable<>(); validateS3CredentialHelper( "session-token-c", metadataManager, revokedSTSTokenTable, false, createSTSTokenIdentifier(), null, null); @@ -102,7 +102,7 @@ public void testValidateS3CredentialWhenMetadataManagerAvailableButRevokedTableN public void testValidateS3CredentialWhenTableThrowsException() throws Exception { // If the revoked STS token table lookup throws, throws INTERNAL_ERROR (wrapped) final OMMetadataManager metadataManager = mock(OMMetadataManager.class); - final Table revokedSTSTokenTable = spy(new InMemoryTestTable<>()); + final Table revokedSTSTokenTable = spy(new InMemoryTestTable<>()); doThrow(new RuntimeException("lookup failed")).when(revokedSTSTokenTable).getIfExist(anyString()); validateS3CredentialHelper( "session-token-g", metadataManager, revokedSTSTokenTable, false, createSTSTokenIdentifier(), @@ -110,7 +110,7 @@ public void testValidateS3CredentialWhenTableThrowsException() throws Exception } private void validateS3CredentialHelper(String sessionToken, OMMetadataManager metadataManager, - Table revokedSTSTokenTable, boolean isRevoked, STSTokenIdentifier stsTokenIdentifier, + Table revokedSTSTokenTable, boolean isRevoked, STSTokenIdentifier stsTokenIdentifier, OMException.ResultCodes expectedResult, String expectedMessageContents) throws Exception { try (OzoneManager ozoneManager = mock(OzoneManager.class)) { @@ -124,10 +124,8 @@ private void validateS3CredentialHelper(String sessionToken, OMMetadataManager m final String tempAccessKeyId = "temp-access-key-id"; if (isRevoked) { - if (revokedSTSTokenTable == null) { - throw new IllegalArgumentException("revokedSTSTokenTable must not be null when isRevoked=true"); - } - revokedSTSTokenTable.put(tempAccessKeyId, sessionToken); + final long insertionTimeMillis = CLOCK.millis(); + revokedSTSTokenTable.put(tempAccessKeyId, insertionTimeMillis); } try (MockedStatic stsSecurityUtilMock = mockStatic(STSSecurityUtil.class, CALLS_REAL_METHODS); diff --git a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/ClientProtocolStub.java b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/ClientProtocolStub.java index b56c6ca3fe8a..d47627790f5f 100644 --- a/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/ClientProtocolStub.java +++ b/hadoop-ozone/s3gateway/src/test/java/org/apache/hadoop/ozone/client/ClientProtocolStub.java @@ -815,6 +815,6 @@ public AssumeRoleResponseInfo assumeRole( } @Override - public void revokeSTSToken(String accessKeyId, String sessionToken) throws IOException { + public void revokeSTSToken(String accessKeyId) throws IOException { } } From da2669a8a93aba881c0f8100cc155e60e279d349 Mon Sep 17 00:00:00 2001 From: Fabian Morgan Date: Mon, 29 Dec 2025 11:46:59 -0800 Subject: [PATCH 2/2] code review updates for ChenSammi --- .../s3/security/S3RevokeSTSTokenRequest.java | 5 +++-- .../om/request/s3/security/package-info.java | 21 +++++++++++++++++++ 2 files changed, 24 insertions(+), 2 deletions(-) create mode 100644 hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/package-info.java 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 2f926f26d81a..f05370991637 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 @@ -58,7 +58,8 @@ public OMRequest preExecute(OzoneManager ozoneManager) throws IOException { getOmRequest().getRevokeSTSTokenRequest(); // Only S3/Ozone admins can revoke STS tokens by temporary access key ID. - final UserGroupInformation ugi = S3SecretRequestHelper.getOrCreateUgi(getUserInfo().getUserName()); + final OzoneManagerProtocolProtos.UserInfo userInfo = getUserInfo(); + final UserGroupInformation ugi = S3SecretRequestHelper.getOrCreateUgi(userInfo.getUserName()); if (!ozoneManager.isS3Admin(ugi)) { throw new OMException("Only S3/Ozone admins can revoke STS tokens.", OMException.ResultCodes.PERMISSION_DENIED); } @@ -67,7 +68,7 @@ public OMRequest preExecute(OzoneManager ozoneManager) throws IOException { .setRevokeSTSTokenRequest(revokeReq) .setCmdType(getOmRequest().getCmdType()) .setClientId(getOmRequest().getClientId()) - .setUserInfo(getUserInfo()); + .setUserInfo(userInfo); if (getOmRequest().hasTraceID()) { omRequest.setTraceID(getOmRequest().getTraceID()); diff --git a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/package-info.java b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/package-info.java new file mode 100644 index 000000000000..7727afbfc68c --- /dev/null +++ b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/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 S3 Security requests. + */ +package org.apache.hadoop.ozone.om.request.s3.security;