Copilot commented on code in PR #11095:
URL: https://github.com/apache/ozone/pull/11095#discussion_r3842309769


##########
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/STSTokenIdentifier.java:
##########
@@ -146,6 +260,9 @@ public void fromProtoBuf(OMTokenProto token) throws 
IOException {
     setOwnerId(token.getOwner());
     setExpiry(Instant.ofEpochMilli(token.getMaxDate()));
 
+    if (token.hasIssueDate()) {
+      this.creationTime = Instant.ofEpochMilli(token.getIssueDate());
+    }

Review Comment:
   `toProtoBuf()` unconditionally dereferences `creationTime`, but 
`fromProtoBuf()` only sets it when `issueDate` is present. This can cause NPEs 
and/or make older STS tokens (minted before this change) impossible to 
parse/round-trip safely. Consider always initializing `creationTime` in 
`fromProtoBuf()` (eg, a sensible fallback when `issueDate` is absent) and/or 
guarding `toProtoBuf()` so it never dereferences a null `creationTime`.



##########
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/STSTokenIdentifier.java:
##########
@@ -123,6 +236,7 @@ public OMTokenProto toProtoBuf() {
 
     builder
         .setType(OMTokenProto.Type.S3_STS_TOKEN)
+        .setIssueDate(creationTime.toEpochMilli())

Review Comment:
   `toProtoBuf()` unconditionally dereferences `creationTime`, but 
`fromProtoBuf()` only sets it when `issueDate` is present. This can cause NPEs 
and/or make older STS tokens (minted before this change) impossible to 
parse/round-trip safely. Consider always initializing `creationTime` in 
`fromProtoBuf()` (eg, a sensible fallback when `issueDate` is absent) and/or 
guarding `toProtoBuf()` so it never dereferences a null `creationTime`.



##########
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/STSSecurityUtil.java:
##########
@@ -180,6 +180,9 @@ static void 
ensureEssentialFieldsArePresentInToken(STSTokenIdentifier stsTokenId
     if (StringUtils.isEmpty(stsTokenIdentifier.getSecretAccessKey())) {
       throw new SecretManager.InvalidToken("Invalid STS token - 
secretAccessKey is null/empty");
     }
+    if (stsTokenIdentifier.getCreationTime() == null) {
+      throw new SecretManager.InvalidToken("Invalid STS token - creationTime 
is null");
+    }

Review Comment:
   Requiring `creationTime` during validation will reject any previously issued 
STS tokens that do not contain `issueDate` in their serialized form (eg, tokens 
minted before this PR). If preserving in-flight token validity across rolling 
upgrades is required, you likely need a backwards-compatible defaulting 
strategy (eg, set `creationTime` during decode when `issueDate` is missing) 
rather than hard-failing here.



##########
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3RevokeSTSTokenRequest.java:
##########
@@ -61,48 +70,94 @@ public S3RevokeSTSTokenRequest(OMRequest omRequest) {
   @Override
   public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
     final OMRequest omRequest = super.preExecute(ozoneManager);
-    final OzoneManagerProtocolProtos.RevokeSTSTokenRequest revokeReq =
-        omRequest.getRevokeSTSTokenRequest();
+    final RevokeSTSTokenRequest revokeReq = 
omRequest.getRevokeSTSTokenRequest();
+    validateRevokeRequestFields(revokeReq);
 
-    // Get the original (long-lived) access key id from the session token
-    // and enforce the same permission model that is used for S3 secret
+    // Use the original (long-lived) access key ID from the request and enforce
+    // the same permission model that is used for S3 secret
     // operations (get/set/revoke). Only the owner of the original access
     // key (i.e. the creator of the STS token) or an S3 / tenant admin is 
allowed
     // to revoke its temporary STS credentials.
-    final String sessionToken = revokeReq.getSessionToken();
-    final STSTokenIdentifier stsTokenIdentifier = 
STSSecurityUtil.constructValidateAndDecryptSTSToken(
-        sessionToken, ozoneManager.getSecretKeyClient(), CLOCK);
-    final String originalAccessKeyId = 
stsTokenIdentifier.getOriginalAccessKeyId();
+    final String originalAccessKeyId = revokeReq.getOriginalAccessKeyId();
 
     final UserGroupInformation ugi = 
S3SecretRequestHelper.getOrCreateUgi(originalAccessKeyId);
     S3SecretRequestHelper.checkAccessIdSecretOpPermission(ozoneManager, ugi, 
originalAccessKeyId);
 
-    return omRequest;
+    if (!ozoneManager.getS3SecretManager().hasS3Secret(originalAccessKeyId)) {
+      throw new OMException("originalAccessKeyId does not exist: " + 
originalAccessKeyId, INVALID_REQUEST);
+    }
+
+    final long revocationTimeMillis = CLOCK.millis();
+    final UpdateRevokeSTSTokenRequest updateRevokeSTSTokenRequest = 
UpdateRevokeSTSTokenRequest.newBuilder()
+        .setOriginalAccessKeyId(originalAccessKeyId)
+        .setRevocationTimeMillis(revocationTimeMillis)
+        .build();
+
+    return omRequest.toBuilder()
+        .setUpdateRevokeSTSTokenRequest(updateRevokeSTSTokenRequest)
+        .build();
   }
 
   @Override
   public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, 
ExecutionContext context) {
     final OMResponse.Builder omResponse = 
OmResponseUtil.getOMResponseBuilder(getOmRequest());
+    IOException exception = null;
+    OMClientResponse omClientResponse;
+    String originalAccessKeyId = null;
+
+    try {
+      validateReplicatedRevokeRequestFields(getOmRequest());
+      final UpdateRevokeSTSTokenRequest updateRevokeSTSTokenRequest = 
getOmRequest().getUpdateRevokeSTSTokenRequest();
+      originalAccessKeyId = 
updateRevokeSTSTokenRequest.getOriginalAccessKeyId();
+      final long revocationTimeMillis = 
updateRevokeSTSTokenRequest.getRevocationTimeMillis();
 
-    final OzoneManagerProtocolProtos.RevokeSTSTokenRequest revokeReq = 
getOmRequest().getRevokeSTSTokenRequest();
-    final String sessionToken = revokeReq.getSessionToken();
+      // All actual DB mutations are done in the response's addToDBBatch().
+      omClientResponse = new S3RevokeSTSTokenResponse(originalAccessKeyId, 
revocationTimeMillis, omResponse.build());
 
-    // All actual DB mutations are done in the response's addToDBBatch().
-    final OMClientResponse omClientResponse = new S3RevokeSTSTokenResponse(
-        sessionToken, omResponse.build());
+      // Update the cache immediately so subsequent validation checks see the 
revocation
+      
ozoneManager.getMetadataManager().getS3RevokedStsTokenTable().addCacheEntry(
+          new CacheKey<>(originalAccessKeyId), 
CacheValue.get(context.getIndex(), revocationTimeMillis));
+
+      LOG.info(
+          "Marked STS tokens as revoked for originalAccessKeyId={} with cutoff 
time {}.",
+          originalAccessKeyId, revocationTimeMillis);
+    } catch (IOException ex) {
+      exception = ex;
+      omClientResponse = new S3RevokeSTSTokenResponse(null, 0L, 
createErrorOMResponse(omResponse, ex));
+    }
 
     // Audit log
     final Map<String, String> auditMap = new HashMap<>();
     final OzoneManagerProtocolProtos.UserInfo userInfo = 
getOmRequest().getUserInfo();
     auditMap.put(OzoneConsts.S3_REVOKESTSTOKEN_USER, userInfo.getUserName());
-    markForAudit(ozoneManager.getAuditLogger(), buildAuditMessage(
-        OMAction.REVOKE_STS_TOKEN, auditMap, null, userInfo));
+    if (originalAccessKeyId != null) {
+      auditMap.put(OzoneConsts.S3_STS_ORIGINAL_ACCESS_KEY_ID, 
originalAccessKeyId);
+    }
+    markForAudit(
+        ozoneManager.getAuditLogger(), 
buildAuditMessage(OMAction.REVOKE_STS_TOKEN, auditMap, exception, userInfo));
+    return omClientResponse;
+  }
 
-    // Update the cache immediately so subsequent validation checks see the 
revocation
-    
ozoneManager.getMetadataManager().getS3RevokedStsTokenTable().addCacheEntry(
-        new CacheKey<>(sessionToken), CacheValue.get(context.getIndex(), 
CLOCK.millis()));
+  private static void validateRevokeRequestFields(RevokeSTSTokenRequest 
revokeReq) throws OMException {
+    final String originalAccessKeyId = revokeReq.getOriginalAccessKeyId();
+    if (StringUtils.isEmpty(originalAccessKeyId)) {
+      throw new OMException("originalAccessKeyId is required for STS token 
revocation", INVALID_REQUEST);
+    }
+    if (originalAccessKeyId.length() >= 
OzoneConsts.OZONE_MAXIMUM_ACCESS_ID_LENGTH) {
+      throw new OMException("originalAccessKeyId length is invalid: " + 
originalAccessKeyId.length(), INVALID_REQUEST);

Review Comment:
   The length validation error message is missing the permitted maximum, which 
makes it hard to diagnose. Consider including the max allowed length (eg, 
`...invalid: X (max Y)`), and ideally the constraint definition 
(`OZONE_MAXIMUM_ACCESS_ID_LENGTH`).



##########
hadoop-ozone/cli-shell/src/main/java/org/apache/hadoop/ozone/shell/s3/RevokeSTSTokenHandler.java:
##########
@@ -29,18 +29,18 @@
 /**
  * Executes revocation of STS tokens.
  *
- * <p>This command marks the specified STS token as revoked by adding it to 
the OM's revoked STS token table.
- * Subsequent S3 requests using the same session token will be rejected once 
the revocation
- * state has propagated.</p>
+ * <p>This command records a revocation cutoff for the given original access 
key ID in the OM's
+ * revoked STS token table. Subsequent S3 requests using STS tokens created 
before that cutoff
+ * will be rejected once the revocation state has propagated.</p>
  */
 @Command(name = "revokeststoken",
-    description = "Revoke S3 STS token for the given session token")
+    description = "Revoke S3 STS tokens for the given original access key ID")
 public class RevokeSTSTokenHandler extends S3Handler {
 
-  @Option(names = "-t",
+  @Option(names = {"-o", "--original-access-key-id"},
       required = true,
-      description = "STS session token")
-  private String sessionToken;
+      description = "Original long-lived access key ID whose STS tokens should 
be revoked")
+  private String originalAccessKeyId;

Review Comment:
   This changes the CLI option from `-t` (session token) to `-o` (original 
access key ID), which is a breaking CLI/API change for existing scripts. If 
backward compatibility is important, consider keeping `-t` as a deprecated 
alias and translating it client-side (eg, best-effort extraction of 
`originalAccessKeyId` from the provided token) or at least emitting a targeted 
error that guides users to the new flag.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]


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

Reply via email to