This is an automated email from the ASF dual-hosted git repository.
sodonnell pushed a commit to branch HDDS-13323-sts
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/HDDS-13323-sts by this push:
new e96df8e2003 HDDS-13887. [STS] Protobuf Plumbing for AssumeRole
Requests (#9254)
e96df8e2003 is described below
commit e96df8e20039b8d7e81dcfcc9c40b6cd9f184abc
Author: fmorg-git <[email protected]>
AuthorDate: Wed Nov 12 11:38:06 2025 -0800
HDDS-13887. [STS] Protobuf Plumbing for AssumeRole Requests (#9254)
---
.../apache/hadoop/ozone/client/ObjectStore.java | 20 ++
.../ozone/client/protocol/ClientProtocol.java | 17 ++
.../apache/hadoop/ozone/client/rpc/RpcClient.java | 11 +
.../main/java/org/apache/hadoop/ozone/OmUtils.java | 1 +
.../ozone/om/helpers/AssumeRoleResponseInfo.java | 133 ++++++++++
.../ozone/om/protocol/OzoneManagerProtocol.java | 22 ++
...OzoneManagerProtocolClientSideTranslatorPB.java | 24 ++
.../om/helpers/TestAssumeRoleResponseInfo.java | 286 +++++++++++++++++++++
.../src/main/proto/OmClientProtocol.proto | 27 ++
.../org/apache/hadoop/ozone/audit/OMAction.java | 2 +
.../hadoop/ozone/client/ClientProtocolStub.java | 11 +
11 files changed, 554 insertions(+)
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 456dc916214..18e28f387c6 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
@@ -36,6 +36,7 @@
import org.apache.hadoop.ozone.OzoneFsServerDefaults;
import org.apache.hadoop.ozone.client.protocol.ClientProtocol;
import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.om.helpers.AssumeRoleResponseInfo;
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
import org.apache.hadoop.ozone.om.helpers.DeleteTenantState;
import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs;
@@ -750,6 +751,25 @@ public Iterator<OzoneSnapshotDiff> listSnapshotDiffJobs(
return new SnapshotDiffJobIterator(volumeName, bucketName, jobStatus,
listAllStatus, prevSnapshotDiffJob);
}
+ /**
+ * Process the AssumeRole operation.
+ *
+ * @param roleArn The ARN of the role to assume
+ * @param roleSessionName The session name (should be unique) for
this operation
+ * @param durationSeconds The duration in seconds for the token
validity
+ * @param awsIamSessionPolicy The AWS IAM JSON session policy
+ * @return AssumeRoleResponseInfo The AssumeRole response information
containing temporary credentials
+ * @throws IOException if an error occurs during the AssumeRole
operation
+ */
+ public AssumeRoleResponseInfo assumeRole(
+ String roleArn,
+ String roleSessionName,
+ int durationSeconds,
+ String awsIamSessionPolicy
+ ) throws IOException {
+ return proxy.assumeRole(roleArn, roleSessionName, durationSeconds,
awsIamSessionPolicy);
+ }
+
/**
* An Iterator to iterate over {@link SnapshotDiffJobIterator} list.
*/
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 e3a57589634..7560f2efc61 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
@@ -46,6 +46,7 @@
import org.apache.hadoop.ozone.client.io.OzoneOutputStream;
import org.apache.hadoop.ozone.om.OMConfigKeys;
import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.om.helpers.AssumeRoleResponseInfo;
import org.apache.hadoop.ozone.om.helpers.DeleteTenantState;
import org.apache.hadoop.ozone.om.helpers.ErrorInfo;
import org.apache.hadoop.ozone.om.helpers.LeaseKeyInfo;
@@ -1359,4 +1360,20 @@ void putObjectTagging(String volumeName, String
bucketName, String keyName,
void deleteObjectTagging(String volumeName, String bucketName, String
keyName)
throws IOException;
+ /**
+ * Process the AssumeRole operation.
+ *
+ * @param roleArn The ARN of the role to assume
+ * @param roleSessionName The session name (should be unique) for
this operation
+ * @param durationSeconds The duration in seconds for the token
validity
+ * @param awsIamSessionPolicy The AWS IAM JSON session policy
+ * @return AssumeRoleResponseInfo The AssumeRole response information
containing temporary credentials
+ * @throws IOException if an error occurs during the AssumeRole
operation
+ */
+ AssumeRoleResponseInfo assumeRole(
+ String roleArn,
+ String roleSessionName,
+ int durationSeconds,
+ String awsIamSessionPolicy
+ ) 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 d4ebf0be1b3..115aa0bd20c 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
@@ -127,6 +127,7 @@
import org.apache.hadoop.ozone.client.protocol.ClientProtocol;
import org.apache.hadoop.ozone.om.OmConfig;
import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.om.helpers.AssumeRoleResponseInfo;
import org.apache.hadoop.ozone.om.helpers.BasicOmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.BucketEncryptionKeyInfo;
import org.apache.hadoop.ozone.om.helpers.BucketLayout;
@@ -2790,6 +2791,16 @@ public void deleteObjectTagging(String volumeName,
String bucketName,
ozoneManagerClient.deleteObjectTagging(keyArgs);
}
+ @Override
+ public AssumeRoleResponseInfo assumeRole(
+ String roleArn,
+ String roleSessionName,
+ int durationSeconds,
+ String awsIamSessionPolicy
+ ) throws IOException {
+ return ozoneManagerClient.assumeRole(roleArn, roleSessionName,
durationSeconds, awsIamSessionPolicy);
+ }
+
private static ExecutorService createThreadPoolExecutor(
int corePoolSize, int maximumPoolSize, String threadNameFormat) {
return new ThreadPoolExecutor(corePoolSize, maximumPoolSize,
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
index 4c20b380865..be1c422711a 100644
--- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
+++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/OmUtils.java
@@ -300,6 +300,7 @@ public static boolean isReadOnly(
case CompleteMultiPartUpload:
case AbortMultiPartUpload:
case GetS3Secret:
+ case AssumeRole:
case GetDelegationToken:
case RenewDelegationToken:
case CancelDelegationToken:
diff --git
a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/AssumeRoleResponseInfo.java
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/AssumeRoleResponseInfo.java
new file mode 100644
index 00000000000..08bf14ef4a2
--- /dev/null
+++
b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/AssumeRoleResponseInfo.java
@@ -0,0 +1,133 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.helpers;
+
+import java.util.Objects;
+import net.jcip.annotations.Immutable;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.AssumeRoleResponse;
+
+/**
+ * Utility class to handle AssumeRoleResponse protobuf message.
+ */
+@Immutable
+public class AssumeRoleResponseInfo {
+
+ private final String accessKeyId;
+ private final String secretAccessKey;
+ private final String sessionToken;
+ private final long expirationEpochSeconds;
+ private final String assumedRoleId;
+
+ public String getAccessKeyId() {
+ return accessKeyId;
+ }
+
+ public String getSecretAccessKey() {
+ return secretAccessKey;
+ }
+
+ public String getSessionToken() {
+ return sessionToken;
+ }
+
+ public long getExpirationEpochSeconds() {
+ return expirationEpochSeconds;
+ }
+
+ public String getAssumedRoleId() {
+ return assumedRoleId;
+ }
+
+ public AssumeRoleResponseInfo(
+ String accessKeyId,
+ String secretAccessKey,
+ String sessionToken,
+ long expirationEpochSeconds,
+ String assumedRoleId
+ ) {
+ this.accessKeyId = accessKeyId;
+ this.secretAccessKey = secretAccessKey;
+ this.sessionToken = sessionToken;
+ this.expirationEpochSeconds = expirationEpochSeconds;
+ this.assumedRoleId = assumedRoleId;
+ }
+
+ public static AssumeRoleResponseInfo fromProtobuf(
+ AssumeRoleResponse response
+ ) {
+ return new AssumeRoleResponseInfo(
+ response.getAccessKeyId(),
+ response.getSecretAccessKey(),
+ response.getSessionToken(),
+ response.getExpirationEpochSeconds(),
+ response.getAssumedRoleId()
+ );
+ }
+
+ public AssumeRoleResponse getProtobuf() {
+ return AssumeRoleResponse.newBuilder()
+ .setAccessKeyId(accessKeyId)
+ .setSecretAccessKey(secretAccessKey)
+ .setSessionToken(sessionToken)
+ .setExpirationEpochSeconds(expirationEpochSeconds)
+ .setAssumedRoleId(assumedRoleId)
+ .build();
+ }
+
+ @Override
+ public String toString() {
+ return "AssumeRoleResponseInfo{" +
+ "accessKeyId='" + accessKeyId + '\'' +
+ ", secretAccessKey='" + secretAccessKey + '\'' +
+ ", sessionToken='" + sessionToken + '\'' +
+ ", expirationEpochSeconds=" + expirationEpochSeconds +
+ ", assumedRoleId='" + assumedRoleId + '\'' +
+ '}';
+ }
+
+ @Override
+ public boolean equals(
+ Object o
+ ) {
+ if (this == o) {
+ return true;
+ }
+
+ if (o == null || getClass() != o.getClass()) {
+ return false;
+ }
+
+ final AssumeRoleResponseInfo that = (AssumeRoleResponseInfo) o;
+ return expirationEpochSeconds == that.expirationEpochSeconds &&
+ Objects.equals(accessKeyId, that.accessKeyId) &&
+ Objects.equals(secretAccessKey, that.secretAccessKey) &&
+ Objects.equals(sessionToken, that.sessionToken) &&
+ Objects.equals(assumedRoleId, that.assumedRoleId);
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ accessKeyId,
+ secretAccessKey,
+ sessionToken,
+ expirationEpochSeconds,
+ assumedRoleId
+ );
+ }
+}
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 3bcf190662a..b41510bb2bf 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
@@ -29,6 +29,7 @@
import org.apache.hadoop.ozone.om.IOmMetadataReader;
import org.apache.hadoop.ozone.om.OMConfigKeys;
import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.om.helpers.AssumeRoleResponseInfo;
import org.apache.hadoop.ozone.om.helpers.DBUpdates;
import org.apache.hadoop.ozone.om.helpers.DeleteTenantState;
import org.apache.hadoop.ozone.om.helpers.ErrorInfo;
@@ -1175,4 +1176,25 @@ default void deleteObjectTagging(OmKeyArgs args) throws
IOException {
* @throws IOException
*/
void startQuotaRepair(List<String> buckets) throws IOException;
+
+ /**
+ * Process the AssumeRole operation.
+ *
+ * @param roleArn The ARN of the role to assume
+ * @param roleSessionName The session name (should be unique) for
this operation
+ * @param durationSeconds The duration in seconds for the token
validity
+ * @param awsIamSessionPolicy The AWS IAM JSON session policy
+ * @return AssumeRoleResponseInfo The AssumeRole response information
containing temporary credentials
+ * @throws IOException if an error occurs during the AssumeRole
operation
+ */
+ default AssumeRoleResponseInfo assumeRole(
+ String roleArn,
+ String roleSessionName,
+ int durationSeconds,
+ String awsIamSessionPolicy
+ ) 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 671a93a486e..222f4bc1f48 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
@@ -53,6 +53,7 @@
import org.apache.hadoop.ozone.ClientVersion;
import org.apache.hadoop.ozone.OzoneAcl;
import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.om.helpers.AssumeRoleResponseInfo;
import org.apache.hadoop.ozone.om.helpers.BasicOmKeyInfo;
import org.apache.hadoop.ozone.om.helpers.DBUpdates;
import org.apache.hadoop.ozone.om.helpers.DeleteTenantState;
@@ -2650,6 +2651,29 @@ public void deleteObjectTagging(OmKeyArgs args) throws
IOException {
handleError(omResponse);
}
+ @Override
+ public AssumeRoleResponseInfo assumeRole(
+ String roleArn,
+ String roleSessionName,
+ int durationSeconds,
+ String awsIamSessionPolicy
+ ) throws IOException {
+ final OzoneManagerProtocolProtos.AssumeRoleRequest.Builder request =
+ OzoneManagerProtocolProtos.AssumeRoleRequest.newBuilder()
+ .setRoleArn(roleArn)
+ .setRoleSessionName(roleSessionName)
+ .setDurationSeconds(durationSeconds)
+ .setAwsIamSessionPolicy(awsIamSessionPolicy != null ?
awsIamSessionPolicy : "");
+
+ final OMRequest omRequest = createOMRequest(Type.AssumeRole)
+ .setAssumeRoleRequest(request)
+ .build();
+
+ return AssumeRoleResponseInfo.fromProtobuf(
+ handleError(submitRequest(omRequest)).getAssumeRoleResponse()
+ );
+ }
+
private SafeMode toProtoBuf(SafeModeAction action) {
switch (action) {
case ENTER:
diff --git
a/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestAssumeRoleResponseInfo.java
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestAssumeRoleResponseInfo.java
new file mode 100644
index 00000000000..db5a409864d
--- /dev/null
+++
b/hadoop-ozone/common/src/test/java/org/apache/hadoop/ozone/om/helpers/TestAssumeRoleResponseInfo.java
@@ -0,0 +1,286 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.hadoop.ozone.om.helpers;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.AssumeRoleResponse;
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test AssumeRoleResponseInfo.
+ */
+public class TestAssumeRoleResponseInfo {
+
+ private static final String ACCESS_KEY_ID = "ASIA7O1AJD8VV4KCEAX5";
+ private static final String SECRET_ACCESS_KEY =
"wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY";
+ private static final String SESSION_TOKEN =
"jgIDCAMaI2lkYnJva2VyL2lkYnJva2VyY2xpZW50QEVYQU1QTEUuQ09" +
+
"NOLDJ8bClM2IjaWRicm9rZXIvaWRicm9rZXJjbGllbnRARVhBTVBMRS5DT02CASRjMGM5YTk2NS00YTU1LTRmMjQtYTUxMi0"
+
+
"3MGQ3M2JiMzg0ZDSKARRBU0lBN08xQUpEOFdWNEtDRUFYNZIBKGFybjphd3M6aWFtOjoxMjM0NTY3ODkwMTI6cm9sZS9mbS1"
+
+
"kd3JvbGWaAXAvdmNOSjNqRW5zc3UyWklKYWxJbGRXZSswV1VmYkRvSmwxdXV1eDBPVExQalVzZ0VqOVE5T0FZVUZTd2JtUGo"
+
+
"zZHNhaXpjMytacEJiVXJDNWRSV1FOTE4xcWJsVkhSdEZiZFBPTXp4NU5YY1pXdz09ogHQAVt7InJvbGVOYW1lIjoiZm0tZHd"
+
+
"yb2xlIiwiZ3JhbnRzIjpbeyJvYmplY3RzIjpbImtleTogL3Mzdi9idWNrZXQxLyoiXSwicGVybWlzc2lvbnMiOlsicmVhZCJ"
+
+
"dfSx7Im9iamVjdHMiOlsidm9sdW1lOiAvczN2Il0sInBlcm1pc3Npb25zIjpbInJlYWQiXX0seyJvYmplY3RzIjpbImJ1Y2t"
+
+
"ldDogL3Mzdi9idWNrZXQxIl0sInBlcm1pc3Npb25zIjpbInJlYWQiXX1dfV0gCil_LhVjpP4hfMez4L5wNZDeqEubSeBfEow"
+
+ "VoRnSQ-wIU1RTVG9rZW4DU1RT";
+ private static final long EXPIRATION_EPOCH_SECONDS = 1577836800L;
+ private static final String ASSUMED_ROLE_ID =
"arn:aws:iam::123456789012:role/MyRole";
+
+ @Test
+ public void testConstructor() {
+ final AssumeRoleResponseInfo response = new AssumeRoleResponseInfo(
+ ACCESS_KEY_ID,
+ SECRET_ACCESS_KEY,
+ SESSION_TOKEN,
+ EXPIRATION_EPOCH_SECONDS,
+ ASSUMED_ROLE_ID
+ );
+
+ assertEquals(ACCESS_KEY_ID, response.getAccessKeyId());
+ assertEquals(SECRET_ACCESS_KEY, response.getSecretAccessKey());
+ assertEquals(SESSION_TOKEN, response.getSessionToken());
+ assertEquals(EXPIRATION_EPOCH_SECONDS,
response.getExpirationEpochSeconds());
+ assertEquals(ASSUMED_ROLE_ID, response.getAssumedRoleId());
+ }
+
+ @Test
+ public void testProtobufConversion() {
+ final AssumeRoleResponseInfo response = new AssumeRoleResponseInfo(
+ ACCESS_KEY_ID,
+ SECRET_ACCESS_KEY,
+ SESSION_TOKEN,
+ EXPIRATION_EPOCH_SECONDS,
+ ASSUMED_ROLE_ID
+ );
+
+ final AssumeRoleResponse proto = response.getProtobuf();
+
+ assertNotNull(proto);
+ assertEquals(ACCESS_KEY_ID, proto.getAccessKeyId());
+ assertEquals(SECRET_ACCESS_KEY, proto.getSecretAccessKey());
+ assertEquals(SESSION_TOKEN, proto.getSessionToken());
+ assertEquals(EXPIRATION_EPOCH_SECONDS, proto.getExpirationEpochSeconds());
+ assertEquals(ASSUMED_ROLE_ID, proto.getAssumedRoleId());
+ }
+
+ @Test
+ public void testFromProtobuf() {
+ final AssumeRoleResponse proto = AssumeRoleResponse.newBuilder()
+ .setAccessKeyId(ACCESS_KEY_ID)
+ .setSecretAccessKey(SECRET_ACCESS_KEY)
+ .setSessionToken(SESSION_TOKEN)
+ .setExpirationEpochSeconds(EXPIRATION_EPOCH_SECONDS)
+ .setAssumedRoleId(ASSUMED_ROLE_ID)
+ .build();
+
+ final AssumeRoleResponseInfo response =
AssumeRoleResponseInfo.fromProtobuf(proto);
+
+ assertEquals(ACCESS_KEY_ID, response.getAccessKeyId());
+ assertEquals(SECRET_ACCESS_KEY, response.getSecretAccessKey());
+ assertEquals(SESSION_TOKEN, response.getSessionToken());
+ assertEquals(EXPIRATION_EPOCH_SECONDS,
response.getExpirationEpochSeconds());
+ assertEquals(ASSUMED_ROLE_ID, response.getAssumedRoleId());
+ }
+
+ @Test
+ public void testProtobufRoundTrip() {
+ final AssumeRoleResponseInfo originalResponse = new AssumeRoleResponseInfo(
+ ACCESS_KEY_ID,
+ SECRET_ACCESS_KEY,
+ SESSION_TOKEN,
+ EXPIRATION_EPOCH_SECONDS,
+ ASSUMED_ROLE_ID
+ );
+
+ final AssumeRoleResponse proto = originalResponse.getProtobuf();
+ final AssumeRoleResponseInfo recoveredResponse =
AssumeRoleResponseInfo.fromProtobuf(proto);
+
+ assertEquals(originalResponse, recoveredResponse);
+ }
+
+ @Test
+ public void testEqualsAndHashCodeWithIdenticalObjects() {
+ final AssumeRoleResponseInfo response1 = new AssumeRoleResponseInfo(
+ ACCESS_KEY_ID,
+ SECRET_ACCESS_KEY,
+ SESSION_TOKEN,
+ EXPIRATION_EPOCH_SECONDS,
+ ASSUMED_ROLE_ID
+ );
+
+ final AssumeRoleResponseInfo response2 = new AssumeRoleResponseInfo(
+ ACCESS_KEY_ID,
+ SECRET_ACCESS_KEY,
+ SESSION_TOKEN,
+ EXPIRATION_EPOCH_SECONDS,
+ ASSUMED_ROLE_ID
+ );
+
+ assertEquals(response1, response2);
+ assertEquals(response1.hashCode(), response2.hashCode());
+ }
+
+ @Test
+ public void testNotEqualsAndHashCodeWithDifferentAccessKeyId() {
+ final AssumeRoleResponseInfo response1 = new AssumeRoleResponseInfo(
+ ACCESS_KEY_ID,
+ SECRET_ACCESS_KEY,
+ SESSION_TOKEN,
+ EXPIRATION_EPOCH_SECONDS,
+ ASSUMED_ROLE_ID
+ );
+
+ final AssumeRoleResponseInfo response2 = new AssumeRoleResponseInfo(
+ "DIFFERENT_KEY_ID",
+ SECRET_ACCESS_KEY,
+ SESSION_TOKEN,
+ EXPIRATION_EPOCH_SECONDS,
+ ASSUMED_ROLE_ID
+ );
+
+ assertNotEquals(response1, response2);
+ assertNotEquals(response1.hashCode(), response2.hashCode());
+ }
+
+ @Test
+ public void testNotEqualsAndHashCodeWithDifferentSecretAccessKey() {
+ final AssumeRoleResponseInfo response1 = new AssumeRoleResponseInfo(
+ ACCESS_KEY_ID,
+ SECRET_ACCESS_KEY,
+ SESSION_TOKEN,
+ EXPIRATION_EPOCH_SECONDS,
+ ASSUMED_ROLE_ID
+ );
+
+ final AssumeRoleResponseInfo response2 = new AssumeRoleResponseInfo(
+ ACCESS_KEY_ID,
+ "DIFFERENT_SECRET_KEY",
+ SESSION_TOKEN,
+ EXPIRATION_EPOCH_SECONDS,
+ ASSUMED_ROLE_ID
+ );
+
+ assertNotEquals(response1, response2);
+ assertNotEquals(response1.hashCode(), response2.hashCode());
+ }
+
+ @Test
+ public void testNotEqualsAndHashCodeWithDifferentSessionToken() {
+ final AssumeRoleResponseInfo response1 = new AssumeRoleResponseInfo(
+ ACCESS_KEY_ID,
+ SECRET_ACCESS_KEY,
+ SESSION_TOKEN,
+ EXPIRATION_EPOCH_SECONDS,
+ ASSUMED_ROLE_ID
+ );
+
+ final AssumeRoleResponseInfo response2 = new AssumeRoleResponseInfo(
+ ACCESS_KEY_ID,
+ SECRET_ACCESS_KEY,
+ "DIFFERENT_TOKEN",
+ EXPIRATION_EPOCH_SECONDS,
+ ASSUMED_ROLE_ID
+ );
+
+ assertNotEquals(response1, response2);
+ assertNotEquals(response1.hashCode(), response2.hashCode());
+ }
+
+ @Test
+ public void testNotEqualsAndHashCodeWithDifferentExpirationEpochSeconds() {
+ final AssumeRoleResponseInfo response1 = new AssumeRoleResponseInfo(
+ ACCESS_KEY_ID,
+ SECRET_ACCESS_KEY,
+ SESSION_TOKEN,
+ EXPIRATION_EPOCH_SECONDS,
+ ASSUMED_ROLE_ID
+ );
+
+ final AssumeRoleResponseInfo response2 = new AssumeRoleResponseInfo(
+ ACCESS_KEY_ID,
+ SECRET_ACCESS_KEY,
+ SESSION_TOKEN,
+ 9999999999L,
+ ASSUMED_ROLE_ID
+ );
+
+ assertNotEquals(response1, response2);
+ assertNotEquals(response1.hashCode(), response2.hashCode());
+ }
+
+ @Test
+ public void testNotEqualsAndHashCodeWithDifferentAssumedRoleId() {
+ final AssumeRoleResponseInfo response1 = new AssumeRoleResponseInfo(
+ ACCESS_KEY_ID,
+ SECRET_ACCESS_KEY,
+ SESSION_TOKEN,
+ EXPIRATION_EPOCH_SECONDS,
+ ASSUMED_ROLE_ID
+ );
+
+ final AssumeRoleResponseInfo response2 = new AssumeRoleResponseInfo(
+ ACCESS_KEY_ID,
+ SECRET_ACCESS_KEY,
+ SESSION_TOKEN,
+ EXPIRATION_EPOCH_SECONDS,
+ "DIFFERENT_ROLE_ID"
+ );
+
+ assertNotEquals(response1, response2);
+ assertNotEquals(response1.hashCode(), response2.hashCode());
+ }
+
+ @Test
+ public void testNotEqualsWithNull() {
+ final AssumeRoleResponseInfo response = new AssumeRoleResponseInfo(
+ ACCESS_KEY_ID,
+ SECRET_ACCESS_KEY,
+ SESSION_TOKEN,
+ EXPIRATION_EPOCH_SECONDS,
+ ASSUMED_ROLE_ID
+ );
+
+ assertNotEquals(null, response);
+ }
+
+ @Test
+ public void testToString() {
+ final AssumeRoleResponseInfo response = new AssumeRoleResponseInfo(
+ ACCESS_KEY_ID,
+ SECRET_ACCESS_KEY,
+ SESSION_TOKEN,
+ EXPIRATION_EPOCH_SECONDS,
+ ASSUMED_ROLE_ID
+ );
+
+ final String toString = response.toString();
+ final String expectedString = "AssumeRoleResponseInfo{" +
+ "accessKeyId='" + ACCESS_KEY_ID + '\'' +
+ ", secretAccessKey='" + SECRET_ACCESS_KEY + '\'' +
+ ", sessionToken='" + SESSION_TOKEN + '\'' +
+ ", expirationEpochSeconds=" + EXPIRATION_EPOCH_SECONDS +
+ ", assumedRoleId='" + ASSUMED_ROLE_ID + '\'' +
+ '}';
+
+ assertNotNull(toString);
+ assertEquals(expectedString, toString);
+ }
+}
+
diff --git
a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
index 1e5675f612e..8e455e70342 100644
--- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
+++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto
@@ -156,6 +156,7 @@ enum Type {
PutObjectTagging = 140;
GetObjectTagging = 141;
DeleteObjectTagging = 142;
+ AssumeRole = 143;
}
enum SafeMode {
@@ -304,6 +305,7 @@ message OMRequest {
optional PutObjectTaggingRequest putObjectTaggingRequest =
141;
optional DeleteObjectTaggingRequest deleteObjectTaggingRequest =
142;
repeated SetSnapshotPropertyRequest SetSnapshotPropertyRequests =
143;
+ optional AssumeRoleRequest assumeRoleRequest =
144;
}
message OMResponse {
@@ -437,6 +439,7 @@ message OMResponse {
optional GetObjectTaggingResponse getObjectTaggingResponse =
140;
optional PutObjectTaggingResponse putObjectTaggingResponse =
141;
optional DeleteObjectTaggingResponse deleteObjectTaggingResponse =
142;
+ optional AssumeRoleResponse assumeRoleResponse =
143;
}
enum Status {
@@ -1494,6 +1497,7 @@ message OMTokenProto {
enum Type {
DELEGATION_TOKEN = 1;
S3AUTHINFO = 2;
+ S3_STS_TOKEN = 3;
};
required Type type = 1;
optional uint32 version = 2;
@@ -1511,6 +1515,11 @@ message OMTokenProto {
optional string strToSign = 14;
optional string omServiceId = 15 [deprecated = true];
optional string secretKeyId = 16;
+ // STS-specific fields
+ optional string roleArn = 17;
+ optional string originalAccessKeyId = 18;
+ optional string secretAccessKey = 19;
+ optional string sessionPolicy = 20;
}
message SecretKeyProto {
@@ -2263,6 +2272,9 @@ message S3Authentication {
optional string stringToSign = 1;
optional string signature = 2;
optional string accessId = 3;
+ // If present, indicates this request uses STS temporary credentials
+ // and carries the base64-encoded session token for validation.
+ optional string sessionToken = 4;
}
message RecoverLeaseRequest {
@@ -2354,6 +2366,21 @@ message DeleteObjectTaggingRequest {
message DeleteObjectTaggingResponse {
}
+message AssumeRoleRequest {
+ required string roleArn = 1;
+ required string roleSessionName = 2;
+ optional int32 durationSeconds = 3 [default = 3600];
+ optional string awsIamSessionPolicy = 4;
+}
+
+message AssumeRoleResponse {
+ required string accessKeyId = 1;
+ required string secretAccessKey = 2;
+ required string sessionToken = 3;
+ required uint64 expirationEpochSeconds = 4;
+ required string assumedRoleId = 5;
+}
+
/**
The OM service that takes care of Ozone namespace.
*/
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/audit/OMAction.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/audit/OMAction.java
index f728a88b2b3..9be2bdea709 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/audit/OMAction.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/audit/OMAction.java
@@ -83,6 +83,8 @@ public enum OMAction implements AuditAction {
SET_S3_SECRET,
REVOKE_S3_SECRET,
+ S3_ASSUME_ROLE,
+
CREATE_TENANT,
DELETE_TENANT,
LIST_TENANT,
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 739babce1d0..ef0d32e2387 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
@@ -37,6 +37,7 @@
import org.apache.hadoop.ozone.client.io.OzoneInputStream;
import org.apache.hadoop.ozone.client.io.OzoneOutputStream;
import org.apache.hadoop.ozone.client.protocol.ClientProtocol;
+import org.apache.hadoop.ozone.om.helpers.AssumeRoleResponseInfo;
import org.apache.hadoop.ozone.om.helpers.DeleteTenantState;
import org.apache.hadoop.ozone.om.helpers.ErrorInfo;
import org.apache.hadoop.ozone.om.helpers.LeaseKeyInfo;
@@ -803,4 +804,14 @@ public void deleteObjectTagging(String volumeName, String
bucketName, String key
getBucket(volumeName, bucketName).deleteObjectTagging(keyName);
}
+ @Override
+ public AssumeRoleResponseInfo assumeRole(
+ String roleArn,
+ String roleSessionName,
+ int durationSeconds,
+ String awsIamSessionPolicy
+ ) throws IOException {
+ return null;
+ }
+
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]