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

chungen0126 pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git


The following commit(s) were added to refs/heads/master by this push:
     new 208b031453c HDDS-15140. Piggyback S3 derived key during key creation 
(#10652)
208b031453c is described below

commit 208b031453cc001060d745212ff02f88256c8bec
Author: Chung En Lee <[email protected]>
AuthorDate: Wed Aug 19 04:06:08 2026 +0800

    HDDS-15140. Piggyback S3 derived key during key creation (#10652)
---
 .../apache/hadoop/ozone/client/OzoneBucket.java    |  73 ++++++++++++++
 .../ozone/client/io/OzoneDataStreamOutput.java     |   8 ++
 .../hadoop/ozone/client/io/OzoneOutputStream.java  |  10 ++
 .../ozone/client/protocol/ClientProtocol.java      |  76 ++++++++++++++
 .../apache/hadoop/ozone/client/rpc/RpcClient.java  | 112 +++++++++++++++++++--
 hadoop-ozone/common/pom.xml                        |   4 +
 .../hadoop/ozone/om}/AWSV4AuthValidator.java       |  35 ++-----
 .../apache/hadoop/ozone/om/helpers/OmKeyArgs.java  |  13 +++
 .../hadoop/ozone/om/helpers/OpenKeySession.java    |  10 ++
 ...OzoneManagerProtocolClientSideTranslatorPB.java |   7 +-
 .../src/main/proto/OmClientProtocol.proto          |   2 +
 hadoop-ozone/ozone-manager/pom.xml                 |   4 -
 .../org/apache/hadoop/ozone/om/OzoneManager.java   |   5 +
 .../ozone/om/request/key/OMKeyCreateRequest.java   |  40 +++++++-
 .../om/request/key/OMKeyCreateRequestWithFSO.java  |   8 +-
 .../OzoneDelegationTokenSecretManager.java         |   1 +
 .../hadoop/ozone/security/S3SecurityUtil.java      |   2 +-
 .../om/request/key/TestOMKeyCreateRequest.java     | 105 +++++++++++++++++++
 .../ozone/security/TestAWSV4AuthValidator.java     |   1 +
 19 files changed, 468 insertions(+), 48 deletions(-)

diff --git 
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneBucket.java
 
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneBucket.java
index fe1cd7b8f2b..9b5f663b7f0 100644
--- 
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneBucket.java
+++ 
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/OzoneBucket.java
@@ -499,6 +499,16 @@ public OzoneOutputStream createKey(String key, long size,
         .createKey(volumeName, name, key, size, replicationConfig, 
keyMetadata, tags);
   }
 
+  public OzoneOutputStream createKey(String key, long size,
+      ReplicationConfig replicationConfig,
+      Map<String, String> keyMetadata,
+      Map<String, String> tags,
+      boolean derivedKeyPiggyBacking)
+      throws IOException {
+    return proxy
+        .createKey(volumeName, name, key, size, replicationConfig, 
keyMetadata, tags, derivedKeyPiggyBacking);
+  }
+
   /**
    * This API allows to atomically update an existing key. The key read before 
invoking this API
    * should remain unchanged for this key to be written. This is controlled by 
the generation
@@ -539,6 +549,13 @@ public OzoneOutputStream createKeyIfNotExists(String 
keyName, long size,
         replicationConfig, metadata, tags);
   }
 
+  public OzoneOutputStream createKeyIfNotExists(String keyName, long size,
+      ReplicationConfig replicationConfig, Map<String, String> metadata,
+      Map<String, String> tags, boolean derivedKeyPiggyBacking) throws 
IOException {
+    return proxy.createKeyIfNotExists(volumeName, name, keyName, size,
+        replicationConfig, metadata, tags, derivedKeyPiggyBacking);
+  }
+
   /**
    * Rewrites a key only if its ETag matches (S3 If-Match semantics).
    *
@@ -559,6 +576,15 @@ public OzoneOutputStream rewriteKeyIfMatch(String keyName, 
long size,
         expectedETag, replicationConfig, metadata, tags);
   }
 
+  public OzoneOutputStream rewriteKeyIfMatch(String keyName, long size,
+      String expectedETag, ReplicationConfig replicationConfig,
+      Map<String, String> metadata, Map<String, String> tags,
+      boolean derivedKeyPiggyBacking)
+      throws IOException {
+    return proxy.rewriteKeyIfMatch(volumeName, name, keyName, size,
+        expectedETag, replicationConfig, metadata, tags, 
derivedKeyPiggyBacking);
+  }
+
   /**
    * Creates a new key in the bucket, with default replication type RATIS and
    * with replication factor THREE.
@@ -614,6 +640,17 @@ public OzoneDataStreamOutput createStreamKey(String key, 
long size,
         replicationConfig, keyMetadata, tags);
   }
 
+  public OzoneDataStreamOutput createStreamKey(String key, long size,
+      ReplicationConfig replicationConfig, Map<String, String> keyMetadata,
+      Map<String, String> tags, boolean derivedKeyPiggyBacking)
+      throws IOException {
+    if (replicationConfig == null) {
+      replicationConfig = defaultReplication;
+    }
+    return proxy.createStreamKey(volumeName, name, key, size,
+        replicationConfig, keyMetadata, tags, derivedKeyPiggyBacking);
+  }
+
   /**
    * Creates a key with datastream only if it does not exist already
    * (S3 If-None-Match: * semantics).
@@ -636,6 +673,16 @@ public OzoneDataStreamOutput 
createStreamKeyIfNotExists(String key, long size,
         replicationConfig, keyMetadata, tags);
   }
 
+  public OzoneDataStreamOutput createStreamKeyIfNotExists(String key, long 
size,
+      ReplicationConfig replicationConfig, Map<String, String> keyMetadata,
+      Map<String, String> tags, boolean derivedKeyPiggyBacking) throws 
IOException {
+    if (replicationConfig == null) {
+      replicationConfig = defaultReplication;
+    }
+    return proxy.createStreamKeyIfNotExists(volumeName, name, key, size,
+        replicationConfig, keyMetadata, tags, derivedKeyPiggyBacking);
+  }
+
   /**
    * Rewrites a key with datastream only if its ETag matches
    * (S3 If-Match semantics).
@@ -660,6 +707,18 @@ public OzoneDataStreamOutput 
rewriteStreamKeyIfMatch(String key, long size,
         expectedETag, replicationConfig, keyMetadata, tags);
   }
 
+  public OzoneDataStreamOutput rewriteStreamKeyIfMatch(String key, long size,
+      String expectedETag, ReplicationConfig replicationConfig,
+      Map<String, String> keyMetadata, Map<String, String> tags,
+      boolean derivedKeyPiggyBacking)
+      throws IOException {
+    if (replicationConfig == null) {
+      replicationConfig = defaultReplication;
+    }
+    return proxy.rewriteStreamKeyIfMatch(volumeName, name, key, size,
+        expectedETag, replicationConfig, keyMetadata, tags, 
derivedKeyPiggyBacking);
+  }
+
   /**
    * Reads an existing key from the bucket.
    *
@@ -921,6 +980,14 @@ public OzoneOutputStream createMultipartKey(String key, 
long size,
         uploadID);
   }
 
+  public OzoneOutputStream createMultipartKey(String key, long size,
+                                              int partNumber, String uploadID,
+                                              boolean derivedKeyPiggyBacking)
+      throws IOException {
+    return proxy.createMultipartKey(volumeName, name, key, size, partNumber,
+        uploadID, derivedKeyPiggyBacking);
+  }
+
   /**
    * Create a part key for a multipart upload key.
    * @param key
@@ -936,6 +1003,12 @@ public OzoneDataStreamOutput 
createMultipartStreamKey(String key,
             key, size, partNumber, uploadID);
   }
 
+  public OzoneDataStreamOutput createMultipartStreamKey(String key,
+      long size, int partNumber, String uploadID, boolean 
derivedKeyPiggyBacking) throws IOException {
+    return proxy.createMultipartStreamKey(volumeName, name,
+            key, size, partNumber, uploadID, derivedKeyPiggyBacking);
+  }
+
   /**
    * Complete Multipart upload. This will combine all the parts and make the
    * key visible in ozone.
diff --git 
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/io/OzoneDataStreamOutput.java
 
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/io/OzoneDataStreamOutput.java
index 52e79ae5f12..9d87150b2b4 100644
--- 
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/io/OzoneDataStreamOutput.java
+++ 
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/io/OzoneDataStreamOutput.java
@@ -39,6 +39,7 @@ public class OzoneDataStreamOutput extends 
ByteBufferOutputStream
   private final ByteBufferStreamOutput byteBufferStreamOutput;
   private boolean enableHsync;
   private final Syncable syncable;
+  private ByteBuffer derivedKey;
 
   /**
    * Constructs an instance with a {@link Syncable} {@link OutputStream}.
@@ -195,4 +196,11 @@ public Map<String, String> getMetadata() {
     return ((KeyMetadataAware)this.byteBufferStreamOutput).getMetadata();
   }
 
+  public ByteBuffer getDerivedKey() {
+    return derivedKey;
+  }
+
+  public void setDerivedKey(ByteBuffer derivedKey) {
+    this.derivedKey = derivedKey;
+  }
 }
diff --git 
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/io/OzoneOutputStream.java
 
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/io/OzoneOutputStream.java
index a7eda7da284..38dbff8c5fd 100644
--- 
a/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/io/OzoneOutputStream.java
+++ 
b/hadoop-ozone/client/src/main/java/org/apache/hadoop/ozone/client/io/OzoneOutputStream.java
@@ -19,6 +19,7 @@
 
 import java.io.IOException;
 import java.io.OutputStream;
+import java.nio.ByteBuffer;
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
@@ -37,6 +38,7 @@ public class OzoneOutputStream extends ByteArrayStreamOutput
   private final OutputStream outputStream;
   private final Syncable syncable;
   private boolean enableHsync;
+  private ByteBuffer derivedKey;
 
   /**
    * Constructs an instance with a {@link Syncable} {@link OutputStream}.
@@ -181,4 +183,12 @@ private static OutputStream unwrap(OutputStream out) {
     }
     return out;
   }
+
+  public ByteBuffer getDerivedKey() {
+    return derivedKey;
+  }
+
+  public void setDerivedKey(ByteBuffer derivedKey) {
+    this.derivedKey = derivedKey;
+  }
 }
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 71ca47cef06..a8e75eed746 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
@@ -521,6 +521,82 @@ OzoneDataStreamOutput rewriteStreamKeyIfMatch(String 
volumeName,
       ReplicationConfig replicationConfig, Map<String, String> metadata,
       Map<String, String> tags) throws IOException;
 
+  @SuppressWarnings("checkstyle:parameternumber")
+  default OzoneOutputStream createKey(String volumeName, String bucketName,
+      String keyName, long size, ReplicationConfig replicationConfig,
+      Map<String, String> metadata, Map<String, String> tags,
+      boolean derivedKeyPiggyBacking) throws IOException {
+    return createKey(volumeName, bucketName, keyName, size, replicationConfig,
+        metadata, tags);
+  }
+
+  @SuppressWarnings("checkstyle:parameternumber")
+  default OzoneOutputStream createKeyIfNotExists(String volumeName, String 
bucketName,
+      String keyName, long size, ReplicationConfig replicationConfig,
+      Map<String, String> metadata, Map<String, String> tags,
+      boolean derivedKeyPiggyBacking) throws IOException {
+    return createKeyIfNotExists(volumeName, bucketName, keyName, size, 
replicationConfig,
+        metadata, tags);
+  }
+
+  @SuppressWarnings("checkstyle:parameternumber")
+  default OzoneOutputStream rewriteKeyIfMatch(String volumeName, String 
bucketName,
+      String keyName, long size, String expectedETag,
+      ReplicationConfig replicationConfig, Map<String, String> metadata,
+      Map<String, String> tags, boolean derivedKeyPiggyBacking) throws 
IOException {
+    return rewriteKeyIfMatch(volumeName, bucketName, keyName, size, 
expectedETag,
+        replicationConfig, metadata, tags);
+  }
+
+  @SuppressWarnings("checkstyle:parameternumber")
+  default OzoneOutputStream createMultipartKey(String volumeName, String 
bucketName,
+                                       String keyName, long size,
+                                       int partNumber, String uploadID,
+                                       boolean derivedKeyPiggyBacking)
+      throws IOException {
+    return createMultipartKey(volumeName, bucketName, keyName, size, 
partNumber,
+        uploadID);
+  }
+
+  @SuppressWarnings("checkstyle:parameternumber")
+  default OzoneDataStreamOutput createStreamKey(String volumeName, String 
bucketName,
+      String keyName, long size, ReplicationConfig replicationConfig,
+      Map<String, String> metadata, Map<String, String> tags,
+      boolean derivedKeyPiggyBacking) throws IOException {
+    return createStreamKey(volumeName, bucketName, keyName, size, 
replicationConfig,
+        metadata, tags);
+  }
+
+  @SuppressWarnings("checkstyle:parameternumber")
+  default OzoneDataStreamOutput createStreamKeyIfNotExists(String volumeName,
+      String bucketName, String keyName, long size,
+      ReplicationConfig replicationConfig, Map<String, String> metadata,
+      Map<String, String> tags, boolean derivedKeyPiggyBacking) throws 
IOException {
+    return createStreamKeyIfNotExists(volumeName, bucketName, keyName, size,
+        replicationConfig, metadata, tags);
+  }
+
+  @SuppressWarnings("checkstyle:parameternumber")
+  default OzoneDataStreamOutput rewriteStreamKeyIfMatch(String volumeName,
+      String bucketName, String keyName, long size, String expectedETag,
+      ReplicationConfig replicationConfig, Map<String, String> metadata,
+      Map<String, String> tags, boolean derivedKeyPiggyBacking) throws 
IOException {
+    return rewriteStreamKeyIfMatch(volumeName, bucketName, keyName, size, 
expectedETag,
+        replicationConfig, metadata, tags);
+  }
+
+  @SuppressWarnings("checkstyle:parameternumber")
+  default OzoneDataStreamOutput createMultipartStreamKey(String volumeName,
+                                                 String bucketName,
+                                                 String keyName, long size,
+                                                 int partNumber,
+                                                 String uploadID,
+                                                 boolean 
derivedKeyPiggyBacking)
+      throws IOException {
+    return createMultipartStreamKey(volumeName, bucketName, keyName, size,
+        partNumber, uploadID);
+  }
+
   /**
    * Reads a key from an existing bucket.
    * @param volumeName Name of the Volume
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 893fc90138c..01b7b8d9796 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
@@ -1404,10 +1404,21 @@ public OzoneOutputStream createKey(
       String volumeName, String bucketName, String keyName, long size,
       ReplicationConfig replicationConfig,
       Map<String, String> metadata, Map<String, String> tags) throws 
IOException {
+    return createKey(volumeName, bucketName, keyName, size, replicationConfig,
+        metadata, tags, false);
+  }
+
+  @Override
+  public OzoneOutputStream createKey(
+      String volumeName, String bucketName, String keyName, long size,
+      ReplicationConfig replicationConfig,
+      Map<String, String> metadata, Map<String, String> tags,
+      boolean derivedKeyPiggyBacking) throws IOException {
     String ownerName = getRealUserInfo().getShortUserName();
     OmKeyArgs.Builder builder = createWriteKeyArgsBuilder(volumeName,
         bucketName, keyName, size, replicationConfig, metadata, tags);
     builder.setOwnerName(ownerName);
+    builder.setDerivedKeyPiggyBacking(derivedKeyPiggyBacking);
     return openOutputStream(builder.build(), size);
   }
 
@@ -1433,6 +1444,15 @@ public OzoneOutputStream createKeyIfNotExists(String 
volumeName,
       String bucketName, String keyName, long size,
       ReplicationConfig replicationConfig, Map<String, String> metadata,
       Map<String, String> tags) throws IOException {
+    return createKeyIfNotExists(volumeName, bucketName, keyName, size,
+        replicationConfig, metadata, tags, false);
+  }
+
+  @Override
+  public OzoneOutputStream createKeyIfNotExists(String volumeName,
+      String bucketName, String keyName, long size,
+      ReplicationConfig replicationConfig, Map<String, String> metadata,
+      Map<String, String> tags, boolean derivedKeyPiggyBacking) throws 
IOException {
     if (omVersion.compareTo(OzoneManagerVersion.ATOMIC_REWRITE_KEY) < 0) {
       throw new IOException(
           "OzoneManager does not support atomic key creation.");
@@ -1441,15 +1461,25 @@ public OzoneOutputStream createKeyIfNotExists(String 
volumeName,
         bucketName, keyName, size, replicationConfig, metadata, tags);
     builder.setExpectedDataGeneration(
         OzoneConsts.EXPECTED_GEN_CREATE_IF_ABSENT);
+    builder.setDerivedKeyPiggyBacking(derivedKeyPiggyBacking);
     return openOutputStream(builder.build(), size);
   }
 
   @Override
-  @SuppressWarnings("checkstyle:parameternumber")
   public OzoneOutputStream rewriteKeyIfMatch(String volumeName,
       String bucketName, String keyName, long size, String expectedETag,
       ReplicationConfig replicationConfig, Map<String, String> metadata,
       Map<String, String> tags) throws IOException {
+    return rewriteKeyIfMatch(volumeName, bucketName, keyName, size, 
expectedETag,
+        replicationConfig, metadata, tags, false);
+  }
+
+  @Override
+  @SuppressWarnings("checkstyle:parameternumber")
+  public OzoneOutputStream rewriteKeyIfMatch(String volumeName,
+      String bucketName, String keyName, long size, String expectedETag,
+      ReplicationConfig replicationConfig, Map<String, String> metadata,
+      Map<String, String> tags, boolean derivedKeyPiggyBacking) throws 
IOException {
     if (omVersion.compareTo(OzoneManagerVersion.ATOMIC_REWRITE_KEY) < 0) {
       throw new IOException(
           "OzoneManager does not support conditional key rewrite.");
@@ -1457,6 +1487,7 @@ public OzoneOutputStream rewriteKeyIfMatch(String 
volumeName,
     OmKeyArgs.Builder builder = createWriteKeyArgsBuilder(volumeName,
         bucketName, keyName, size, replicationConfig, metadata, tags);
     builder.setExpectedETag(expectedETag);
+    builder.setDerivedKeyPiggyBacking(derivedKeyPiggyBacking);
     return openOutputStream(builder.build(), size);
   }
 
@@ -1525,9 +1556,20 @@ public OzoneDataStreamOutput createStreamKey(
       String volumeName, String bucketName, String keyName, long size,
       ReplicationConfig replicationConfig,
       Map<String, String> metadata, Map<String, String> tags) throws 
IOException {
+    return createStreamKey(volumeName, bucketName, keyName, size, 
replicationConfig,
+        metadata, tags, false);
+  }
+
+  @Override
+  public OzoneDataStreamOutput createStreamKey(
+      String volumeName, String bucketName, String keyName, long size,
+      ReplicationConfig replicationConfig,
+      Map<String, String> metadata, Map<String, String> tags,
+      boolean derivedKeyPiggyBacking) throws IOException {
     OmKeyArgs.Builder builder = createStreamKeyArgsBuilder(
         volumeName, bucketName, keyName, size, replicationConfig, metadata,
         tags);
+    builder.setDerivedKeyPiggyBacking(derivedKeyPiggyBacking);
     return openDataStreamOutput(builder.build());
   }
 
@@ -1536,6 +1578,15 @@ public OzoneDataStreamOutput 
createStreamKeyIfNotExists(String volumeName,
       String bucketName, String keyName, long size,
       ReplicationConfig replicationConfig, Map<String, String> metadata,
       Map<String, String> tags) throws IOException {
+    return createStreamKeyIfNotExists(volumeName, bucketName, keyName, size,
+        replicationConfig, metadata, tags, false);
+  }
+
+  @Override
+  public OzoneDataStreamOutput createStreamKeyIfNotExists(String volumeName,
+      String bucketName, String keyName, long size,
+      ReplicationConfig replicationConfig, Map<String, String> metadata,
+      Map<String, String> tags, boolean derivedKeyPiggyBacking) throws 
IOException {
     if (omVersion.compareTo(OzoneManagerVersion.ATOMIC_REWRITE_KEY) < 0) {
       throw new IOException(
           "OzoneManager does not support atomic key creation.");
@@ -1545,15 +1596,25 @@ public OzoneDataStreamOutput 
createStreamKeyIfNotExists(String volumeName,
         tags);
     builder.setExpectedDataGeneration(
         OzoneConsts.EXPECTED_GEN_CREATE_IF_ABSENT);
+    builder.setDerivedKeyPiggyBacking(derivedKeyPiggyBacking);
     return openDataStreamOutput(builder.build());
   }
 
   @Override
-  @SuppressWarnings("checkstyle:parameternumber")
   public OzoneDataStreamOutput rewriteStreamKeyIfMatch(String volumeName,
       String bucketName, String keyName, long size, String expectedETag,
       ReplicationConfig replicationConfig, Map<String, String> metadata,
       Map<String, String> tags) throws IOException {
+    return rewriteStreamKeyIfMatch(volumeName, bucketName, keyName, size, 
expectedETag,
+        replicationConfig, metadata, tags, false);
+  }
+
+  @Override
+  @SuppressWarnings("checkstyle:parameternumber")
+  public OzoneDataStreamOutput rewriteStreamKeyIfMatch(String volumeName,
+      String bucketName, String keyName, long size, String expectedETag,
+      ReplicationConfig replicationConfig, Map<String, String> metadata,
+      Map<String, String> tags, boolean derivedKeyPiggyBacking) throws 
IOException {
     if (omVersion.compareTo(OzoneManagerVersion.ATOMIC_REWRITE_KEY) < 0) {
       throw new IOException(
           "OzoneManager does not support conditional key rewrite.");
@@ -1562,6 +1623,7 @@ public OzoneDataStreamOutput 
rewriteStreamKeyIfMatch(String volumeName,
         volumeName, bucketName, keyName, size, replicationConfig, metadata,
         tags);
     builder.setExpectedETag(expectedETag);
+    builder.setDerivedKeyPiggyBacking(derivedKeyPiggyBacking);
     return openDataStreamOutput(builder.build());
   }
 
@@ -2066,10 +2128,11 @@ public OmMultipartInfo initiateMultipartUpload(String 
volumeName,
     return multipartInfo;
   }
 
+  @SuppressWarnings("checkstyle:parameternumber")
   private OpenKeySession newMultipartOpenKey(
       String volumeName, String bucketName, String keyName,
       long size, int partNumber, String uploadID,
-      boolean sortDatanodesInPipeline) throws IOException {
+      boolean sortDatanodesInPipeline, boolean derivedKeyPiggyBacking) throws 
IOException {
     verifyVolumeName(volumeName);
     verifyBucketName(bucketName);
     if (checkKeyNameEnabled) {
@@ -2094,6 +2157,7 @@ private OpenKeySession newMultipartOpenKey(
         .setMultipartUploadPartNumber(partNumber)
         .setSortDatanodesInPipeline(sortDatanodesInPipeline)
         .setOwnerName(ownerName)
+        .setDerivedKeyPiggyBacking(derivedKeyPiggyBacking)
         .build();
     return ozoneManagerClient.openKey(keyArgs);
   }
@@ -2102,8 +2166,15 @@ private OpenKeySession newMultipartOpenKey(
   public OzoneOutputStream createMultipartKey(
       String volumeName, String bucketName, String keyName,
       long size, int partNumber, String uploadID) throws IOException {
+    return createMultipartKey(volumeName, bucketName, keyName, size, 
partNumber, uploadID, false);
+  }
+
+  @Override
+  public OzoneOutputStream createMultipartKey(
+      String volumeName, String bucketName, String keyName,
+      long size, int partNumber, String uploadID, boolean 
derivedKeyPiggyBacking) throws IOException {
     final OpenKeySession openKey = newMultipartOpenKey(
-        volumeName, bucketName, keyName, size, partNumber, uploadID, false);
+        volumeName, bucketName, keyName, size, partNumber, uploadID, false, 
derivedKeyPiggyBacking);
     return createMultipartOutputStream(openKey, uploadID, partNumber);
   }
 
@@ -2127,8 +2198,21 @@ public OzoneDataStreamOutput createMultipartStreamKey(
       int partNumber,
       String uploadID)
       throws IOException {
+    return createMultipartStreamKey(volumeName, bucketName, keyName, size, 
partNumber, uploadID, false);
+  }
+
+  @Override
+  public OzoneDataStreamOutput createMultipartStreamKey(
+      String volumeName,
+      String bucketName,
+      String keyName,
+      long size,
+      int partNumber,
+      String uploadID,
+      boolean derivedKeyPiggyBacking)
+      throws IOException {
     final OpenKeySession openKey = newMultipartOpenKey(
-        volumeName, bucketName, keyName, size, partNumber, uploadID, true);
+        volumeName, bucketName, keyName, size, partNumber, uploadID, true, 
derivedKeyPiggyBacking);
     final ByteBufferStreamOutput out;
     ReplicationConfig replicationConfig = 
openKey.getKeyInfo().getReplicationConfig();
     if (replicationConfig.getReplicationType() == 
HddsProtos.ReplicationType.RATIS) {
@@ -2147,7 +2231,11 @@ public OzoneDataStreamOutput createMultipartStreamKey(
     } else {
       out = createMultipartOutputStream(openKey, uploadID, partNumber);
     }
-    return new OzoneDataStreamOutput(out, out);
+    OzoneDataStreamOutput ozoneDataStreamOutput = new 
OzoneDataStreamOutput(out, out);
+    if (openKey.getDerivedKey() != null) {
+      ozoneDataStreamOutput.setDerivedKey(openKey.getDerivedKey());
+    }
+    return ozoneDataStreamOutput;
   }
 
   @Override
@@ -2610,7 +2698,11 @@ private OzoneDataStreamOutput 
createDataStreamOutput(OpenKeySession openKey)
     } else {
       out = createOutputStream(openKey);
     }
-    return new OzoneDataStreamOutput(out, out);
+    OzoneDataStreamOutput ozoneDataStreamOutput = new 
OzoneDataStreamOutput(out, out);
+    if (openKey.getDerivedKey() != null) {
+      ozoneDataStreamOutput.setDerivedKey(openKey.getDerivedKey());
+    }
+    return ozoneDataStreamOutput;
   }
 
   private KeyDataStreamOutput.Builder newKeyOutputStreamBuilder() {
@@ -2638,8 +2730,12 @@ private OzoneOutputStream 
createOutputStream(OpenKeySession openKey,
             openKey.getOpenVersion());
     final OzoneOutputStream out = createSecureOutputStream(
         openKey, keyOutputStream, keyOutputStream);
-    return out != null ? out : new OzoneOutputStream(
+    OzoneOutputStream ozoneOutputStream = out != null ? out : new 
OzoneOutputStream(
         keyOutputStream, enableHsync);
+    if (openKey.getDerivedKey() != null) {
+      ozoneOutputStream.setDerivedKey(openKey.getDerivedKey());
+    }
+    return ozoneOutputStream;
   }
 
   private OzoneOutputStream createSecureOutputStream(OpenKeySession openKey,
diff --git a/hadoop-ozone/common/pom.xml b/hadoop-ozone/common/pom.xml
index c5fc6aeb27b..79039d218d7 100644
--- a/hadoop-ozone/common/pom.xml
+++ b/hadoop-ozone/common/pom.xml
@@ -89,6 +89,10 @@
       <groupId>org.apache.httpcomponents</groupId>
       <artifactId>httpcore</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.kerby</groupId>
+      <artifactId>kerby-util</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.apache.ozone</groupId>
       <artifactId>hdds-client</artifactId>
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/AWSV4AuthValidator.java
 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/AWSV4AuthValidator.java
similarity index 78%
rename from 
hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/AWSV4AuthValidator.java
rename to 
hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/AWSV4AuthValidator.java
index 4118894e722..6a2d5628107 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/AWSV4AuthValidator.java
+++ 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/AWSV4AuthValidator.java
@@ -15,7 +15,7 @@
  * limitations under the License.
  */
 
-package org.apache.hadoop.ozone.security;
+package org.apache.hadoop.ozone.om;
 
 import java.nio.charset.StandardCharsets;
 import java.security.GeneralSecurityException;
@@ -33,7 +33,7 @@
  * documentation https://docs.aws.amazon.com/general/latest/gr/
  * sigv4-create-canonical-request.html.
  **/
-final class AWSV4AuthValidator {
+public final class AWSV4AuthValidator {
 
   private static final Logger LOG =
       LoggerFactory.getLogger(AWSV4AuthValidator.class);
@@ -75,22 +75,13 @@ private static byte[] sign(byte[] key, String msg) {
     }
   }
 
-  /**
-   * Returns signing key.
-   *
-   * @param key
-   * @param strToSign
-   *
-   * SignatureKey = HMAC-SHA256(HMAC-SHA256(HMAC-SHA256(HMAC-SHA256("AWS4" +
-   * "<YourSecretAccessKey>","20130524"),"us-east-1"),"s3"),"aws4_request")
-   *
-   * For more details refer to AWS documentation: https://docs.aws.amazon
-   * .com/AmazonS3/latest/API/sig-v4-header-based-auth.html
-   *
-   * */
-  private static byte[] getSigningKey(String key, String strToSign) {
-    String[] signData = StringUtils.split(StringUtils.split(strToSign,
-        '\n')[2], '/');
+  public static byte[] getSigningKey(String key, String strToSign) {
+    String credentialScope = StringUtils.split(strToSign, '\n')[2];
+    return getSigningKeyFromCredentialScope(key, credentialScope);
+  }
+
+  private static byte[] getSigningKeyFromCredentialScope(String key, String 
credentialScope) {
+    String[] signData = StringUtils.split(credentialScope, '/');
     String dateStamp = signData[0];
     String regionName = signData[1];
     String serviceName = signData[2];
@@ -105,14 +96,6 @@ private static byte[] getSigningKey(String key, String 
strToSign) {
     return kSigning;
   }
 
-  /**
-   * Validate request by comparing Signature from request. Returns true if
-   * aws request is legit else returns false.
-   * Signature = HEX(HMAC_SHA256(key, String to Sign))
-   *
-   * For more details refer to AWS documentation: https://docs.aws.amazon.com
-   * /AmazonS3/latest/API/sigv4-streaming.html
-   */
   public static boolean validateRequest(String strToSign, String signature,
       String userKey) {
     String expectedSignature = Hex.encode(sign(getSigningKey(userKey,
diff --git 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmKeyArgs.java
 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmKeyArgs.java
index 5d2de09c48e..5c55d7b9b2e 100644
--- 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmKeyArgs.java
+++ 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OmKeyArgs.java
@@ -62,6 +62,7 @@ public final class OmKeyArgs extends WithMetadata implements 
Auditable {
   // been modified.
   private Long expectedDataGeneration = null;
   private final String expectedETag;
+  private final boolean derivedKeyPiggyBacking;
 
   private OmKeyArgs(Builder b) {
     super(b);
@@ -84,6 +85,7 @@ private OmKeyArgs(Builder b) {
     this.tags = b.tags.build();
     this.expectedDataGeneration = b.expectedDataGeneration;
     this.expectedETag = b.expectedETag;
+    this.derivedKeyPiggyBacking = b.derivedKeyPiggyBacking;
   }
 
   public boolean getIsMultipartKey() {
@@ -170,6 +172,10 @@ public String getExpectedETag() {
     return expectedETag;
   }
 
+  public boolean isDerivedKeyPiggyBacking() {
+    return derivedKeyPiggyBacking;
+  }
+
   @Override
   public Map<String, String> toAuditMap() {
     Map<String, String> auditMap = new LinkedHashMap<>();
@@ -244,6 +250,7 @@ public static class Builder extends WithMetadata.Builder {
     private final MapBuilder<String, String> tags;
     private Long expectedDataGeneration = null;
     private String expectedETag;
+    private boolean derivedKeyPiggyBacking;
 
     public Builder() {
       this(AclListBuilder.empty());
@@ -290,6 +297,7 @@ public Builder(OmKeyArgs obj) {
           obj.forceUpdateContainerCacheFromSCM;
       this.expectedDataGeneration = obj.expectedDataGeneration;
       this.expectedETag = obj.expectedETag;
+      this.derivedKeyPiggyBacking = obj.derivedKeyPiggyBacking;
       this.tags = MapBuilder.of(obj.tags);
       this.acls = AclListBuilder.of(obj.acls);
     }
@@ -430,6 +438,11 @@ public Builder setExpectedETag(String eTag) {
       return this;
     }
 
+    public Builder setDerivedKeyPiggyBacking(boolean derivedKeyPiggyBacking) {
+      this.derivedKeyPiggyBacking = derivedKeyPiggyBacking;
+      return this;
+    }
+
     public OmKeyArgs build() {
       return new OmKeyArgs(this);
     }
diff --git 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OpenKeySession.java
 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OpenKeySession.java
index 125df602b28..e6026cb8483 100644
--- 
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OpenKeySession.java
+++ 
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/OpenKeySession.java
@@ -18,6 +18,7 @@
 package org.apache.hadoop.ozone.om.helpers;
 
 import com.fasterxml.jackson.annotation.JsonProperty;
+import java.nio.ByteBuffer;
 
 /**
  * This class represents a open key "session". A session here means a key is
@@ -32,6 +33,7 @@ public class OpenKeySession {
   // a block that has a create version equals to open version means it will
   // be committed only when this open session is closed.
   private long openVersion;
+  private ByteBuffer derivedKey;
 
   public OpenKeySession(long id, OmKeyInfo info, long version) {
     this.id = id;
@@ -39,6 +41,14 @@ public OpenKeySession(long id, OmKeyInfo info, long version) 
{
     this.openVersion = version;
   }
 
+  public void setDerivedKey(ByteBuffer derivedKey) {
+    this.derivedKey = derivedKey;
+  }
+
+  public ByteBuffer getDerivedKey() {
+    return derivedKey;
+  }
+
   public long getOpenVersion() {
     return this.openVersion;
   }
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 ed1d5c35785..30f32ba2e9d 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
@@ -765,15 +765,20 @@ public OpenKeySession openKey(OmKeyArgs args) throws 
IOException {
     }
 
     req.setKeyArgs(keyArgs.build());
+    req.setDerivedKeyPiggyBacking(args.isDerivedKeyPiggyBacking());
 
     OMRequest omRequest = createOMRequest(Type.CreateKey)
         .setCreateKeyRequest(req)
         .build();
 
     CreateKeyResponse keyResponse = 
handleSubmitRequestAndSCMSafeModeRetry(omRequest).getCreateKeyResponse();
-    return new OpenKeySession(keyResponse.getID(),
+    OpenKeySession openKeySession = new OpenKeySession(keyResponse.getID(),
         OmKeyInfo.getFromProtobuf(keyResponse.getKeyInfo()),
         keyResponse.getOpenVersion());
+    if (keyResponse.hasDerivedKey()) {
+      
openKeySession.setDerivedKey(keyResponse.getDerivedKey().asReadOnlyByteBuffer());
+    }
+    return openKeySession;
   }
 
   private OMResponse handleError(OMResponse resp) throws OMException {
diff --git 
a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto 
b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
index 25de443296c..1cf0033cacb 100644
--- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
+++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
@@ -1361,6 +1361,7 @@ message CreateKeyRequest {
     // Set in OM HA during preExecute step. This way all OM's use same ID in
     // OM HA.
     optional uint64 clientID = 2;
+    optional bool derivedKeyPiggyBacking = 3;
 }
 
 message CreateKeyResponse {
@@ -1369,6 +1370,7 @@ message CreateKeyResponse {
     // (similar to a cookie).
     optional uint64 ID = 3;
     optional uint64 openVersion = 4;
+    optional bytes derivedKey = 5;
 }
 
 message LookupKeyRequest {
diff --git a/hadoop-ozone/ozone-manager/pom.xml 
b/hadoop-ozone/ozone-manager/pom.xml
index 0715e3e9563..9f8a8940351 100644
--- a/hadoop-ozone/ozone-manager/pom.xml
+++ b/hadoop-ozone/ozone-manager/pom.xml
@@ -120,10 +120,6 @@
       <groupId>org.apache.hadoop</groupId>
       <artifactId>hadoop-hdfs-client</artifactId>
     </dependency>
-    <dependency>
-      <groupId>org.apache.kerby</groupId>
-      <artifactId>kerby-util</artifactId>
-    </dependency>
     <dependency>
       <groupId>org.apache.logging.log4j</groupId>
       <artifactId>log4j-api</artifactId>
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 09381bacb3d..ed0b89c5a01 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
@@ -5409,6 +5409,11 @@ public void startQuotaRepair(List<String> buckets) 
throws IOException {
     new QuotaRepairTask(this).repair(buckets);
   }
 
+  public byte[] getS3DerivedKey(String accessId, String signingKey) throws 
IOException {
+    String awsSecretKey = s3SecretManager.getSecretString(accessId);
+    return AWSV4AuthValidator.getSigningKey(awsSecretKey, signingKey);
+  }
+
   @Override
   public Map<String, String> getObjectTagging(final OmKeyArgs args)
       throws IOException {
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java
index 929e46222c0..6059d6c46c7 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequest.java
@@ -22,6 +22,7 @@
 import static 
org.apache.hadoop.ozone.om.request.file.OMFileRequest.OMDirectoryResult.FILE_EXISTS_IN_GIVENPATH;
 import static org.apache.hadoop.ozone.util.MetricUtil.captureLatencyNs;
 
+import com.google.protobuf.ByteString;
 import java.io.IOException;
 import java.nio.file.InvalidPathException;
 import java.nio.file.Paths;
@@ -64,9 +65,12 @@
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.KeyArgs;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMTokenProto;
 import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type;
 import 
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.UserInfo;
 import org.apache.hadoop.ozone.request.validation.RequestProcessingPhase;
+import org.apache.hadoop.ozone.security.OzoneTokenIdentifier;
+import org.apache.hadoop.ozone.security.S3SecurityUtil;
 import org.apache.hadoop.ozone.security.acl.IAccessAuthorizer;
 import org.apache.hadoop.util.Time;
 import org.slf4j.Logger;
@@ -195,7 +199,8 @@ public OMRequest preExecute(OzoneManager ozoneManager) 
throws IOException {
   @SuppressWarnings("methodlength")
   public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager, 
ExecutionContext context) {
     final long trxnLogIndex = context.getIndex();
-    CreateKeyRequest createKeyRequest = getOmRequest().getCreateKeyRequest();
+    OMRequest omRequest = getOmRequest();
+    CreateKeyRequest createKeyRequest = omRequest.getCreateKeyRequest();
 
     KeyArgs keyArgs = createKeyRequest.getKeyArgs();
     Map<String, String> auditMap = buildKeyArgsAuditMap(keyArgs);
@@ -317,6 +322,8 @@ public OMClientResponse validateAndUpdateCache(OzoneManager 
ozoneManager, Execut
       checkBucketQuotaInBytes(omMetadataManager, bucketInfo,
           preAllocatedSpace);
       checkBucketQuotaInNamespace(bucketInfo, numMissingParents + 1L);
+      CreateKeyResponse.Builder builder =
+          getResponseBuilderWithDerivedKey(getOmRequest(), ozoneManager, 
createKeyRequest);
       perfMetrics.addCreateKeyQuotaCheckLatencyNs(Time.monotonicNowNanos() - 
quotaCheckStartTime);
       bucketInfo.incrUsedNamespace(numMissingParents);
 
@@ -334,12 +341,12 @@ public OMClientResponse 
validateAndUpdateCache(OzoneManager ozoneManager, Execut
       omMetadataManager.getOpenKeyTable(getBucketLayout()).addCacheEntry(
           dbOpenKeyName, omKeyInfo, trxnLogIndex);
 
-      // Prepare response
-      omResponse.setCreateKeyResponse(CreateKeyResponse.newBuilder()
-          .setKeyInfo(omKeyInfo.getNetworkProtobuf(getOmRequest().getVersion(),
+      
builder.setKeyInfo(omKeyInfo.getNetworkProtobuf(getOmRequest().getVersion(),
               keyArgs.getLatestVersionLocation()))
           .setID(clientID)
-          .setOpenVersion(openVersion).build())
+          .setOpenVersion(openVersion);
+      // Prepare response
+      omResponse.setCreateKeyResponse(builder.build())
           .setCmdType(Type.CreateKey);
       omClientResponse = new OMKeyCreateResponse(omResponse.build(),
           omKeyInfo, missingParentInfos, clientID, bucketInfo.copyObject());
@@ -458,4 +465,27 @@ public static OMRequest 
blockCreateKeyWithBucketLayoutFromOldClient(
     }
     return req;
   }
+
+  protected CreateKeyResponse.Builder getResponseBuilderWithDerivedKey(
+      OMRequest omRequest, OzoneManager ozoneManager,
+      CreateKeyRequest createKeyRequest) throws IOException {
+    CreateKeyResponse.Builder builder = CreateKeyResponse.newBuilder();
+    if (omRequest.hasS3Authentication() && ozoneManager.isSecurityEnabled()
+        && createKeyRequest.hasDerivedKeyPiggyBacking()
+        && createKeyRequest.getDerivedKeyPiggyBacking()
+    ) {
+      OzoneTokenIdentifier s3Token = 
S3SecurityUtil.constructS3Token(omRequest);
+      if (!s3Token.getTokenType().equals(OMTokenProto.Type.S3AUTHINFO)) {
+        // Piggyback was requested but this token type cannot produce a 
derived key.
+        // S3 Gateway should only set this flag for S3AUTHINFO tokens.
+        LOG.warn("Derived key piggyback requested but token type is {}, " +
+                "not S3AUTHINFO. Derived key will not be returned.",
+            s3Token.getTokenType());
+        return builder;
+      }
+      byte[] derivedKey = 
ozoneManager.getS3DerivedKey(s3Token.getAwsAccessId(), s3Token.getStrToSign());
+      builder.setDerivedKey(ByteString.copyFrom(derivedKey));
+    }
+    return builder;
+  }
 }
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequestWithFSO.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequestWithFSO.java
index 99fabb46de1..3642f96c7fc 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequestWithFSO.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/key/OMKeyCreateRequestWithFSO.java
@@ -184,6 +184,8 @@ public OMClientResponse validateAndUpdateCache(OzoneManager 
ozoneManager, Execut
       checkBucketQuotaInBytes(omMetadataManager, omBucketInfo,
           preAllocatedSpace);
       checkBucketQuotaInNamespace(omBucketInfo, numKeysCreated + 1L);
+      CreateKeyResponse.Builder createKeyResponseBuilder =
+          getResponseBuilderWithDerivedKey(getOmRequest(), ozoneManager, 
createKeyRequest);
       perfMetrics.addCreateKeyQuotaCheckLatencyNs(Time.monotonicNowNanos() - 
quotaCheckStartTime);
       omBucketInfo.incrUsedNamespace(numKeysCreated);
 
@@ -202,11 +204,11 @@ public OMClientResponse 
validateAndUpdateCache(OzoneManager ozoneManager, Execut
       // Prepare response. Sets user given full key name in the 'keyName'
       // attribute in response object.
       int clientVersion = getOmRequest().getVersion();
-      omResponse.setCreateKeyResponse(CreateKeyResponse.newBuilder()
-              .setKeyInfo(omFileInfo.getNetworkProtobuf(keyName, clientVersion,
+      
createKeyResponseBuilder.setKeyInfo(omFileInfo.getNetworkProtobuf(keyName, 
clientVersion,
                   keyArgs.getLatestVersionLocation()))
               .setID(clientID)
-              .setOpenVersion(openVersion).build())
+              .setOpenVersion(openVersion);
+      omResponse.setCreateKeyResponse(createKeyResponseBuilder.build())
               .setCmdType(Type.CreateKey);
       omClientResponse = new OMKeyCreateResponseWithFSO(omResponse.build(),
               omFileInfo, missingParentInfos, clientID,
diff --git 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/OzoneDelegationTokenSecretManager.java
 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/OzoneDelegationTokenSecretManager.java
index 01818aa2d57..acce4015962 100644
--- 
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/OzoneDelegationTokenSecretManager.java
+++ 
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/security/OzoneDelegationTokenSecretManager.java
@@ -44,6 +44,7 @@
 import 
org.apache.hadoop.hdds.security.x509.certificate.client.CertificateClient;
 import org.apache.hadoop.hdds.security.x509.exception.CertificateException;
 import org.apache.hadoop.io.Text;
+import org.apache.hadoop.ozone.om.AWSV4AuthValidator;
 import org.apache.hadoop.ozone.om.OzoneManager;
 import org.apache.hadoop.ozone.om.S3SecretManager;
 import org.apache.hadoop.ozone.om.exceptions.OMException;
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 cbe0ce414fe..860c69242b2 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
@@ -79,7 +79,7 @@ public static void validateS3Credential(OMRequest omRequest,
   /**
    * Construct and return {@link OzoneTokenIdentifier} from {@link OMRequest}.
    */
-  private static OzoneTokenIdentifier constructS3Token(OMRequest omRequest) {
+  public static OzoneTokenIdentifier constructS3Token(OMRequest omRequest) {
     S3Authentication auth = omRequest.getS3Authentication();
     OzoneTokenIdentifier s3Token = new OzoneTokenIdentifier();
     s3Token.setTokenType(S3AUTHINFO);
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyCreateRequest.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyCreateRequest.java
index 108a10bc240..d9837147594 100644
--- 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyCreateRequest.java
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/key/TestOMKeyCreateRequest.java
@@ -1518,6 +1518,111 @@ protected OmKeyInfo checkCreatedPaths(
     return omKeyInfo;
   }
 
+  @Test
+  public void testCreateKeyWithS3DerivedKey() throws Exception {
+    when(ozoneManager.getOzoneLockProvider()).thenReturn(
+        new OzoneLockProvider(true, true));
+    when(ozoneManager.isSecurityEnabled()).thenReturn(true);
+    byte[] expectedDerivedKey = new byte[] {9, 8, 7, 6};
+    when(ozoneManager.getS3DerivedKey(anyString(), 
anyString())).thenReturn(expectedDerivedKey);
+
+    KeyArgs.Builder keyArgs = KeyArgs.newBuilder()
+        .setVolumeName(volumeName)
+        .setBucketName(bucketName)
+        .setKeyName(keyName)
+        .setFactor(((RatisReplicationConfig) 
replicationConfig).getReplicationFactor())
+        .setType(replicationConfig.getReplicationType())
+        .setLatestVersionLocation(true)
+        .setDataSize(100L);
+
+    OzoneManagerProtocolProtos.S3Authentication s3Authentication =
+        OzoneManagerProtocolProtos.S3Authentication.newBuilder()
+            .setAccessId("testAccessId")
+            .setSignature("testSignature")
+            .setStringToSign("testStringToSign")
+            .build();
+
+    CreateKeyRequest createKeyRequest = CreateKeyRequest.newBuilder()
+        .setKeyArgs(keyArgs)
+        .setDerivedKeyPiggyBacking(true)
+        .build();
+
+    OMRequest omRequest = OMRequest.newBuilder()
+        .setCmdType(OzoneManagerProtocolProtos.Type.CreateKey)
+        .setClientId(UUID.randomUUID().toString())
+        .setCreateKeyRequest(createKeyRequest)
+        .setS3Authentication(s3Authentication)
+        .build();
+
+    OMKeyCreateRequest omKeyCreateRequest = getOMKeyCreateRequest(omRequest);
+
+    addVolumeAndBucketToDB(volumeName, bucketName, omMetadataManager, 
getBucketLayout());
+
+    OMRequest modifiedOmRequest = omKeyCreateRequest.preExecute(ozoneManager);
+    omKeyCreateRequest = getOMKeyCreateRequest(modifiedOmRequest);
+
+    OMClientResponse response =
+        omKeyCreateRequest.validateAndUpdateCache(ozoneManager, 100L);
+
+    assertEquals(OK, response.getOMResponse().getStatus());
+    OzoneManagerProtocolProtos.CreateKeyResponse createKeyResponse =
+        response.getOMResponse().getCreateKeyResponse();
+    assertNotNull(createKeyResponse);
+    assertTrue(createKeyResponse.hasDerivedKey());
+    assertEquals(com.google.protobuf.ByteString.copyFrom(expectedDerivedKey), 
createKeyResponse.getDerivedKey());
+  }
+
+  @Test
+  public void testCreateKeyWithoutS3DerivedKey() throws Exception {
+    when(ozoneManager.getOzoneLockProvider()).thenReturn(
+        new OzoneLockProvider(true, true));
+    when(ozoneManager.isSecurityEnabled()).thenReturn(true);
+
+    KeyArgs.Builder keyArgs = KeyArgs.newBuilder()
+        .setVolumeName(volumeName)
+        .setBucketName(bucketName)
+        .setKeyName(keyName)
+        .setFactor(((RatisReplicationConfig) 
replicationConfig).getReplicationFactor())
+        .setType(replicationConfig.getReplicationType())
+        .setLatestVersionLocation(true)
+        .setDataSize(100L);
+
+    OzoneManagerProtocolProtos.S3Authentication s3Authentication =
+        OzoneManagerProtocolProtos.S3Authentication.newBuilder()
+            .setAccessId("testAccessId")
+            .setSignature("testSignature")
+            .setStringToSign("testStringToSign")
+            .build();
+
+    CreateKeyRequest createKeyRequest = CreateKeyRequest.newBuilder()
+        .setKeyArgs(keyArgs)
+        .setDerivedKeyPiggyBacking(false)
+        .build();
+
+    OMRequest omRequest = OMRequest.newBuilder()
+        .setCmdType(OzoneManagerProtocolProtos.Type.CreateKey)
+        .setClientId(UUID.randomUUID().toString())
+        .setCreateKeyRequest(createKeyRequest)
+        .setS3Authentication(s3Authentication)
+        .build();
+
+    OMKeyCreateRequest omKeyCreateRequest = getOMKeyCreateRequest(omRequest);
+
+    addVolumeAndBucketToDB(volumeName, bucketName, omMetadataManager, 
getBucketLayout());
+
+    OMRequest modifiedOmRequest = omKeyCreateRequest.preExecute(ozoneManager);
+    omKeyCreateRequest = getOMKeyCreateRequest(modifiedOmRequest);
+
+    OMClientResponse response =
+        omKeyCreateRequest.validateAndUpdateCache(ozoneManager, 100L);
+
+    assertEquals(OK, response.getOMResponse().getStatus());
+    OzoneManagerProtocolProtos.CreateKeyResponse createKeyResponse =
+        response.getOMResponse().getCreateKeyResponse();
+    assertNotNull(createKeyResponse);
+    assertFalse(createKeyResponse.hasDerivedKey());
+  }
+
   protected long checkIntermediatePaths(Path keyPath) throws Exception {
     // Check intermediate paths are created
     keyPath = keyPath.getParent();
diff --git 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/TestAWSV4AuthValidator.java
 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/TestAWSV4AuthValidator.java
index 5564947c1bb..361c540dfd3 100644
--- 
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/TestAWSV4AuthValidator.java
+++ 
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/security/TestAWSV4AuthValidator.java
@@ -21,6 +21,7 @@
 
 import java.util.Arrays;
 import java.util.Collection;
+import org.apache.hadoop.ozone.om.AWSV4AuthValidator;
 import org.junit.jupiter.params.ParameterizedTest;
 import org.junit.jupiter.params.provider.MethodSource;
 


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

Reply via email to