This is an automated email from the ASF dual-hosted git repository.
siyao pushed a commit to branch HDDS-4944
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/HDDS-4944 by this push:
new 8516765 HDDS-5750. [Multi-Tenant] GetS3Secret should retrieve secret
from new tables as well (#2649)
8516765 is described below
commit 85167656ffa4661df252863cbdd49123de7575a0
Author: Siyao Meng <[email protected]>
AuthorDate: Wed Sep 22 14:46:42 2021 -0700
HDDS-5750. [Multi-Tenant] GetS3Secret should retrieve secret from new
tables as well (#2649)
---
.../om/request/s3/security/S3GetSecretRequest.java | 76 ++--
.../s3/tenant/OMAssignUserToTenantRequest.java | 13 +-
.../response/s3/security/S3GetSecretResponse.java | 6 +
.../s3/tenant/OMAssignUserToTenantResponse.java | 7 +
.../response/s3/tenant/OMTenantCreateResponse.java | 6 +
.../s3/security/TestS3GetSecretRequest.java | 418 +++++++++++++++++++++
.../hadoop/ozone/shell/s3/GetS3SecretHandler.java | 10 +-
7 files changed, 495 insertions(+), 41 deletions(-)
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3GetSecretRequest.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3GetSecretRequest.java
index 44c69e9..781c95c 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3GetSecretRequest.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/security/S3GetSecretRequest.java
@@ -24,6 +24,7 @@ import java.util.Map;
import com.google.common.base.Optional;
import org.apache.commons.codec.digest.DigestUtils;
+import org.apache.hadoop.ozone.om.helpers.OmDBAccessIdInfo;
import org.apache.hadoop.ozone.om.request.util.OmResponseUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -83,6 +84,8 @@ public class S3GetSecretRequest extends OMClientRequest {
OMException.ResultCodes.USER_MISMATCH);
}
+ // Generate secret. Used only when doesn't the kerberosID entry doesn't
+ // exist in DB, discarded otherwise.
String s3Secret = DigestUtils.sha256Hex(OmUtils.getSHADigest());
UpdateGetS3SecretRequest updateGetS3SecretRequest =
@@ -126,38 +129,48 @@ public class S3GetSecretRequest extends OMClientRequest {
String kerberosID = updateGetS3SecretRequest.getKerberosID();
try {
String awsSecret = updateGetS3SecretRequest.getAwsSecret();
- acquiredLock =
- omMetadataManager.getLock().acquireWriteLock(S3_SECRET_LOCK,
- kerberosID);
-
- S3SecretValue s3SecretValue =
- omMetadataManager.getS3SecretTable().get(kerberosID);
-
- // If s3Secret for user is not in S3Secret table, add the Secret to
cache.
- if (s3SecretValue == null) {
- omMetadataManager.getS3SecretTable().addCacheEntry(
- new CacheKey<>(kerberosID),
- new CacheValue<>(Optional.of(new S3SecretValue(kerberosID,
- awsSecret)), transactionLogIndex));
+ // Note: We use the same S3_SECRET_LOCK for TenantAccessIdTable.
+ acquiredLock = omMetadataManager.getLock()
+ .acquireWriteLock(S3_SECRET_LOCK, kerberosID);
+
+ // Check multi-tenant table first: tenantAccessIdTable
+ final S3SecretValue assignS3SecretValue;
+ final OmDBAccessIdInfo omDBAccessIdInfo =
+ omMetadataManager.getTenantAccessIdTable().get(kerberosID);
+ if (omDBAccessIdInfo == null) {
+ // Not found in TenantAccessIdTable. Fallback to S3SecretTable.
+ final S3SecretValue s3SecretValue =
+ omMetadataManager.getS3SecretTable().get(kerberosID);
+
+ if (s3SecretValue == null) {
+ // Still not found in S3SecretTable. Will add new entry in this case.
+ assignS3SecretValue = new S3SecretValue(kerberosID, awsSecret);
+ // Add cache entry first.
+ omMetadataManager.getS3SecretTable().addCacheEntry(
+ new CacheKey<>(kerberosID),
+ new CacheValue<>(
+ Optional.of(assignS3SecretValue), transactionLogIndex));
+ } else {
+ // Found in S3SecretTable.
+ awsSecret = s3SecretValue.getAwsSecret();
+ assignS3SecretValue = null;
+ }
} else {
- // If it already exists, use the existing one.
- awsSecret = s3SecretValue.getAwsSecret();
+ // Found in TenantAccessIdTable.
+ awsSecret = omDBAccessIdInfo.getSharedSecret();
+ assignS3SecretValue = null;
}
- GetS3SecretResponse.Builder getS3SecretResponse = GetS3SecretResponse
- .newBuilder().setS3Secret(S3Secret.newBuilder()
- .setAwsSecret(awsSecret).setKerberosID(kerberosID));
-
- if (s3SecretValue == null) {
- omClientResponse =
- new S3GetSecretResponse(new S3SecretValue(kerberosID, awsSecret),
- omResponse.setGetS3SecretResponse(getS3SecretResponse).build());
- } else {
- // As when it already exists, we don't need to add to DB again. So
- // set the value to null.
- omClientResponse = new S3GetSecretResponse(null,
- omResponse.setGetS3SecretResponse(getS3SecretResponse).build());
- }
+ // Compose response
+ final GetS3SecretResponse.Builder getS3SecretResponse =
+ GetS3SecretResponse.newBuilder().setS3Secret(
+ S3Secret.newBuilder()
+ .setAwsSecret(awsSecret)
+ .setKerberosID(kerberosID));
+ // If entry exists, assignS3SecretValue will be null,
+ // so we won't overwrite the entry.
+ omClientResponse = new S3GetSecretResponse(assignS3SecretValue,
+ omResponse.setGetS3SecretResponse(getS3SecretResponse).build());
} catch (IOException ex) {
exception = ex;
@@ -182,10 +195,9 @@ public class S3GetSecretRequest extends OMClientRequest {
exception, getOmRequest().getUserInfo()));
if (exception == null) {
- LOG.debug("Secret for accessKey:{} is generated Successfully",
- kerberosID);
+ LOG.debug("Successfully generated secret for accessKey '{}'",
kerberosID);
} else {
- LOG.error("Secret for accessKey:{} is generation failed", kerberosID,
+ LOG.error("Failed to generate secret for accessKey '{}': {}", kerberosID,
exception);
}
return omClientResponse;
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMAssignUserToTenantRequest.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMAssignUserToTenantRequest.java
index e49b4b6..31a9b8f 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMAssignUserToTenantRequest.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/s3/tenant/OMAssignUserToTenantRequest.java
@@ -80,7 +80,8 @@ import static
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.VOLUME_L
- Value: <GENERATED_SECRET>
- Release S3_SECRET_LOCK write lock
- New entry in tenantAccessIdTable:
- - Key: New accessId for the user in this tenant. e.g. finance$bob ?
+ - Key: New accessId for the user in this tenant.
+ Example of accessId: [email protected]
- Value: OmDBAccessIdInfo. Has tenantId, kerberosPrincipal, sharedSecret.
- New entry or update existing entry in principalToAccessIdsTable:
- Key: Kerberos principal of the user.
@@ -88,7 +89,7 @@ import static
org.apache.hadoop.ozone.om.lock.OzoneManagerLock.Resource.VOLUME_L
- tenantGroupTable: Add this new user to the default tenant group.
- Key: finance$bob
- Value: finance-users
- - tenantRoleTable: TBD. No-op for prototype.
+ - tenantRoleTable: TBD. No-Op for now.
- Release VOLUME_LOCK write lock
*/
@@ -128,9 +129,10 @@ public class OMAssignUserToTenantRequest extends
OMVolumeRequest {
}
// Won't check tenant existence in preExecute.
- // Won't check Kerberos principal existence at all. TODO: Confirm this.
+ // Won't check Kerberos principal existence.
- // Generate random S3 secret
+ // Generate secret. Used only when doesn't the kerberosID entry doesn't
+ // exist in DB, discarded otherwise.
final String s3Secret = DigestUtils.sha256Hex(OmUtils.getSHADigest());
final UpdateGetS3SecretRequest updateGetS3SecretRequest =
@@ -179,7 +181,7 @@ public class OMAssignUserToTenantRequest extends
OMVolumeRequest {
assert(accessId.equals(request.getAccessId()));
final String volumeName = tenantName; // TODO: Configurable
IOException exception = null;
- String userId = null;
+ String userId;
try {
// Check ACL: requires ozone admin or tenant admin permission
@@ -220,6 +222,7 @@ public class OMAssignUserToTenantRequest extends
OMVolumeRequest {
final S3SecretValue s3SecretValue =
new S3SecretValue(accessId, awsSecret);
+ // Add S3SecretTable cache entry
omMetadataManager.getS3SecretTable().addCacheEntry(
new CacheKey<>(accessId),
new CacheValue<>(Optional.of(s3SecretValue), transactionLogIndex));
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/security/S3GetSecretResponse.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/security/S3GetSecretResponse.java
index 1cd0ce5..29f64ca 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/security/S3GetSecretResponse.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/security/S3GetSecretResponse.java
@@ -18,6 +18,7 @@
package org.apache.hadoop.ozone.om.response.s3.security;
+import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.ozone.om.helpers.S3SecretValue;
import org.apache.hadoop.ozone.om.response.CleanupTableInfo;
@@ -56,4 +57,9 @@ public class S3GetSecretResponse extends OMClientResponse {
s3SecretValue.getKerberosID(), s3SecretValue);
}
}
+
+ @VisibleForTesting
+ public S3SecretValue getS3SecretValue() {
+ return s3SecretValue;
+ }
}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/tenant/OMAssignUserToTenantResponse.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/tenant/OMAssignUserToTenantResponse.java
index 56f3c6d..f8e1faf 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/tenant/OMAssignUserToTenantResponse.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/tenant/OMAssignUserToTenantResponse.java
@@ -18,6 +18,7 @@
*/
package org.apache.hadoop.ozone.om.response.s3.tenant;
+import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.hdds.utils.db.BatchOperation;
import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.ozone.om.helpers.OmDBAccessIdInfo;
@@ -90,6 +91,7 @@ public class OMAssignUserToTenantResponse extends
OMClientResponse {
if (s3SecretValue != null &&
getOMResponse().getStatus() == OzoneManagerProtocolProtos.Status.OK) {
assert(accessId.equals(s3SecretValue.getKerberosID()));
+ // Add S3SecretTable entry
omMetadataManager.getS3SecretTable().putWithBatch(batchOperation,
accessId, s3SecretValue);
}
@@ -103,4 +105,9 @@ public class OMAssignUserToTenantResponse extends
OMClientResponse {
omMetadataManager.getTenantRoleTable().putWithBatch(
batchOperation, principal, roleName);
}
+
+ @VisibleForTesting
+ public OmDBAccessIdInfo getOmDBAccessIdInfo() {
+ return omDBAccessIdInfo;
+ }
}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/tenant/OMTenantCreateResponse.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/tenant/OMTenantCreateResponse.java
index 9e5b481..99905d6 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/tenant/OMTenantCreateResponse.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/response/s3/tenant/OMTenantCreateResponse.java
@@ -18,6 +18,7 @@
*/
package org.apache.hadoop.ozone.om.response.s3.tenant;
+import com.google.common.annotations.VisibleForTesting;
import org.apache.hadoop.hdds.utils.db.BatchOperation;
import org.apache.hadoop.ozone.om.OMMetadataManager;
import org.apache.hadoop.ozone.om.helpers.OmDBTenantInfo;
@@ -103,4 +104,9 @@ public class OMTenantCreateResponse extends
OMClientResponse {
omMetadataManager.getUserTable().putWithBatch(batchOperation, dbUserKey,
userVolumeInfo);
}
+
+ @VisibleForTesting
+ public OmDBTenantInfo getOmDBTenantInfo() {
+ return omTenantInfo;
+ }
}
diff --git
a/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3GetSecretRequest.java
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3GetSecretRequest.java
new file mode 100644
index 0000000..d8f67e9
--- /dev/null
+++
b/hadoop-ozone/ozone-manager/src/test/java/org/apache/hadoop/ozone/om/request/s3/security/TestS3GetSecretRequest.java
@@ -0,0 +1,418 @@
+/**
+ * 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.request.s3.security;
+
+import org.apache.hadoop.hdds.conf.OzoneConfiguration;
+import org.apache.hadoop.ipc.RPC;
+import org.apache.hadoop.ipc.Server;
+import org.apache.hadoop.ipc.Server.Call;
+import org.apache.hadoop.ozone.audit.AuditLogger;
+import org.apache.hadoop.ozone.audit.AuditMessage;
+import org.apache.hadoop.ozone.om.OMConfigKeys;
+import org.apache.hadoop.ozone.om.OMMetadataManager;
+import org.apache.hadoop.ozone.om.OMMetrics;
+import org.apache.hadoop.ozone.om.OMMultiTenantManager;
+import org.apache.hadoop.ozone.om.OmMetadataManagerImpl;
+import org.apache.hadoop.ozone.om.OzoneManager;
+import org.apache.hadoop.ozone.om.exceptions.OMException;
+import org.apache.hadoop.ozone.om.exceptions.OMException.ResultCodes;
+import org.apache.hadoop.ozone.om.helpers.OmDBAccessIdInfo;
+import org.apache.hadoop.ozone.om.helpers.S3SecretValue;
+import org.apache.hadoop.ozone.om.multitenant.Tenant;
+import org.apache.hadoop.ozone.om.ratis.utils.OzoneManagerDoubleBufferHelper;
+import
org.apache.hadoop.ozone.om.request.s3.tenant.OMAssignUserToTenantRequest;
+import org.apache.hadoop.ozone.om.request.s3.tenant.OMTenantCreateRequest;
+import org.apache.hadoop.ozone.om.response.OMClientResponse;
+import org.apache.hadoop.ozone.om.response.s3.security.S3GetSecretResponse;
+import
org.apache.hadoop.ozone.om.response.s3.tenant.OMAssignUserToTenantResponse;
+import org.apache.hadoop.ozone.om.response.s3.tenant.OMTenantCreateResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.AssignUserToTenantRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.CreateTenantRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetS3SecretRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetS3SecretResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.S3Secret;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type;
+import org.apache.hadoop.security.UserGroupInformation;
+import org.apache.hadoop.security.authentication.util.KerberosName;
+import org.junit.After;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.IOException;
+import java.util.UUID;
+
+import static
org.apache.hadoop.ozone.OzoneConsts.TENANT_NAME_USER_NAME_DELIMITER;
+import static
org.apache.hadoop.security.authentication.util.KerberosName.DEFAULT_MECHANISM;
+import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.doNothing;
+import static org.mockito.Mockito.framework;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.spy;
+import static org.mockito.Mockito.when;
+
+/**
+ * Test S3GetSecretRequest.
+ */
+public class TestS3GetSecretRequest {
+
+ @Rule
+ public TemporaryFolder folder = new TemporaryFolder();
+
+ private OzoneManager ozoneManager;
+ private OMMetrics omMetrics;
+ private OMMetadataManager omMetadataManager;
+ private AuditLogger auditLogger;
+ // Set ozoneManagerDoubleBuffer to do nothing.
+ private final OzoneManagerDoubleBufferHelper ozoneManagerDoubleBufferHelper =
+ ((response, transactionIndex) -> null);
+
+ // Multi-tenant related vars
+ private static final String USER_ALICE = "[email protected]";
+ private static final String TENANT_NAME = "finance";
+ private static final String USER_BOB = "[email protected]";
+ private static final String ACCESS_ID_BOB =
+ TENANT_NAME + TENANT_NAME_USER_NAME_DELIMITER + USER_BOB;
+
+ private UserGroupInformation ugiAlice;
+
+ private OMMultiTenantManager omMultiTenantManager;
+ private Tenant tenant;
+
+ @Before
+ public void setUp() throws Exception {
+ KerberosName.setRuleMechanism(DEFAULT_MECHANISM);
+ KerberosName.setRules(
+ "RULE:[2:$1@$0](.*@EXAMPLE.COM)s/@.*//\n" +
+ "RULE:[1:$1@$0](.*@EXAMPLE.COM)s/@.*//\n" +
+ "DEFAULT");
+ ugiAlice = UserGroupInformation.createRemoteUser(USER_ALICE);
+ Assert.assertEquals("alice", ugiAlice.getShortUserName());
+
+ ozoneManager = mock(OzoneManager.class);
+
+ Call call = spy(new Call(1, 1, null, null,
+ RPC.RpcKind.RPC_BUILTIN, new byte[] {1, 2, 3}));
+ // Run as alice, so that Server.getRemoteUser() won't return null.
+ when(call.getRemoteUser()).thenReturn(ugiAlice);
+ Server.getCurCall().set(call);
+
+ omMetrics = OMMetrics.create();
+ OzoneConfiguration conf = new OzoneConfiguration();
+ conf.set(OMConfigKeys.OZONE_OM_DB_DIRS,
+ folder.newFolder().getAbsolutePath());
+ // No need to conf.set(OzoneConfigKeys.OZONE_ADMINISTRATORS, ...) here
+ // as we did the trick earlier with mockito.
+ omMetadataManager = new OmMetadataManagerImpl(conf);
+ when(ozoneManager.getMetrics()).thenReturn(omMetrics);
+ when(ozoneManager.getMetadataManager()).thenReturn(omMetadataManager);
+ when(ozoneManager.isRatisEnabled()).thenReturn(true);
+ auditLogger = mock(AuditLogger.class);
+ when(ozoneManager.getAuditLogger()).thenReturn(auditLogger);
+ doNothing().when(auditLogger).logWrite(any(AuditMessage.class));
+
+ // Multi-tenant related initializations
+ omMultiTenantManager = mock(OMMultiTenantManager.class);
+ tenant = mock(Tenant.class);
+ when(omMultiTenantManager.getTenantInfo(TENANT_NAME)).thenReturn(tenant);
+
when(ozoneManager.getMultiTenantManager()).thenReturn(omMultiTenantManager);
+ }
+
+ @After
+ public void tearDown() throws Exception {
+ omMetrics.unRegister();
+ framework().clearInlineMocks();
+ }
+
+ private OMRequest createTenantRequest(String tenantNameStr) {
+
+ return OMRequest.newBuilder()
+ .setClientId(UUID.randomUUID().toString())
+ .setCmdType(Type.CreateTenant)
+ .setCreateTenantRequest(
+ CreateTenantRequest.newBuilder()
+ .setTenantName(tenantNameStr)
+ .build()
+ ).build();
+ }
+
+ private OMRequest assignUserToTenantRequest(
+ String tenantNameStr, String userPrincipalStr, String accessIdStr) {
+
+ return OMRequest.newBuilder()
+ .setClientId(UUID.randomUUID().toString())
+ .setCmdType(Type.AssignUserToTenant)
+ .setAssignUserToTenantRequest(
+ AssignUserToTenantRequest.newBuilder()
+ .setTenantName(tenantNameStr)
+ .setTenantUsername(userPrincipalStr)
+ .setAccessId(accessIdStr)
+ .build()
+ ).build();
+ }
+
+ private OMRequest s3GetSecretRequest(String userPrincipalStr) {
+
+ return OMRequest.newBuilder()
+ .setClientId(UUID.randomUUID().toString())
+ .setCmdType(Type.GetS3Secret)
+ .setGetS3SecretRequest(
+ GetS3SecretRequest.newBuilder()
+ .setKerberosID(userPrincipalStr)
+ .build()
+ ).build();
+ }
+
+ @Test
+ public void testGetSecretOfAnotherUserAsAdmin() throws IOException {
+
+ // This effectively makes alice an admin.
+ when(ozoneManager.isAdmin(ugiAlice)).thenReturn(true);
+
+ // 1. Get secret of "[email protected]" (as an admin).
+ long txLogIndex = 1;
+
+ // Run preExecute
+ S3GetSecretRequest s3GetSecretRequest =
+ new S3GetSecretRequest(
+ new S3GetSecretRequest(
+ s3GetSecretRequest(ACCESS_ID_BOB)
+ ).preExecute(ozoneManager)
+ );
+
+ // Run validateAndUpdateCache
+ OMClientResponse omClientResponse =
+ s3GetSecretRequest.validateAndUpdateCache(ozoneManager,
+ txLogIndex, ozoneManagerDoubleBufferHelper);
+
+ // Check response type and cast
+ Assert.assertTrue(omClientResponse instanceof S3GetSecretResponse);
+ final S3GetSecretResponse s3GetSecretResponse =
+ (S3GetSecretResponse) omClientResponse;
+
+ // Check response
+ final S3SecretValue s3SecretValue = s3GetSecretResponse.getS3SecretValue();
+ Assert.assertEquals(ACCESS_ID_BOB, s3SecretValue.getKerberosID());
+ final String awsSecret = s3SecretValue.getAwsSecret();
+ Assert.assertNotNull(awsSecret);
+
+ final GetS3SecretResponse getS3SecretResponse =
+ s3GetSecretResponse.getOMResponse().getGetS3SecretResponse();
+ // The secret inside should be the same.
+ final S3Secret s3Secret = getS3SecretResponse.getS3Secret();
+ Assert.assertEquals(ACCESS_ID_BOB, s3Secret.getKerberosID());
+ Assert.assertEquals(awsSecret, s3Secret.getAwsSecret());
+ }
+
+ @Test
+ public void testGetOwnSecretAsNonAdmin() throws IOException {
+
+ // This effectively makes alice a regular user.
+ when(ozoneManager.isAdmin(ugiAlice)).thenReturn(false);
+
+ // 1. Get secret of "alice" (as herself).
+ long txLogIndex = 1;
+
+ // Run preExecute
+ S3GetSecretRequest s3GetSecretRequest1 =
+ new S3GetSecretRequest(
+ new S3GetSecretRequest(
+ s3GetSecretRequest(USER_ALICE)
+ ).preExecute(ozoneManager)
+ );
+
+ // Run validateAndUpdateCache
+ OMClientResponse omClientResponse =
+ s3GetSecretRequest1.validateAndUpdateCache(ozoneManager,
+ txLogIndex, ozoneManagerDoubleBufferHelper);
+
+ // Check response type and cast
+ Assert.assertTrue(omClientResponse instanceof S3GetSecretResponse);
+ final S3GetSecretResponse s3GetSecretResponse =
+ (S3GetSecretResponse) omClientResponse;
+
+ // Check response
+ final S3SecretValue s3SecretValue = s3GetSecretResponse.getS3SecretValue();
+ Assert.assertEquals(USER_ALICE, s3SecretValue.getKerberosID());
+ final String awsSecret1 = s3SecretValue.getAwsSecret();
+ Assert.assertNotNull(awsSecret1);
+
+ final GetS3SecretResponse getS3SecretResponse =
+ s3GetSecretResponse.getOMResponse().getGetS3SecretResponse();
+ // The secret inside should be the same.
+ final S3Secret s3Secret1 = getS3SecretResponse.getS3Secret();
+ Assert.assertEquals(USER_ALICE, s3Secret1.getKerberosID());
+ Assert.assertEquals(awsSecret1, s3Secret1.getAwsSecret());
+
+
+ // 2. Get secret of "alice" (as herself) again.
+ ++txLogIndex;
+
+ // Run preExecute
+ S3GetSecretRequest s3GetSecretRequest2 =
+ new S3GetSecretRequest(
+ new S3GetSecretRequest(
+ s3GetSecretRequest(USER_ALICE)
+ ).preExecute(ozoneManager)
+ );
+
+ // Run validateAndUpdateCache
+ OMClientResponse omClientResponse2 =
+ s3GetSecretRequest2.validateAndUpdateCache(ozoneManager,
+ txLogIndex, ozoneManagerDoubleBufferHelper);
+
+ // Check response type and cast
+ Assert.assertTrue(omClientResponse2 instanceof S3GetSecretResponse);
+ final S3GetSecretResponse s3GetSecretResponse2 =
+ (S3GetSecretResponse) omClientResponse2;
+
+ // Check response
+ Assert.assertNull(s3GetSecretResponse2.getS3SecretValue());
+
+ final GetS3SecretResponse getS3SecretResponse2 =
+ s3GetSecretResponse2.getOMResponse().getGetS3SecretResponse();
+ // The secret inside should be the same.
+ final S3Secret s3Secret2 = getS3SecretResponse2.getS3Secret();
+ Assert.assertEquals(USER_ALICE, s3Secret2.getKerberosID());
+
+ // Should get the same secret as the first request's.
+ Assert.assertEquals(awsSecret1, s3Secret2.getAwsSecret());
+ }
+
+ @Test
+ public void testGetSecretOfAnotherUserAsNonAdmin() throws IOException {
+
+ // This effectively makes alice a regular user.
+ when(ozoneManager.isAdmin(ugiAlice)).thenReturn(false);
+
+ // Get secret of "[email protected]" (as another regular user).
+ // Run preExecute, expect USER_MISMATCH
+ try {
+ new S3GetSecretRequest(
+ s3GetSecretRequest(ACCESS_ID_BOB)
+ ).preExecute(ozoneManager);
+ } catch (OMException omEx) {
+ Assert.assertEquals(ResultCodes.USER_MISMATCH, omEx.getResult());
+ return;
+ }
+
+ Assert.fail("Should have thrown OMException because alice should not have "
+ + "the permission to get bob's secret in this test case!");
+ }
+
+ @Test
+ public void testGetSecretWithTenant() throws IOException {
+
+ // This effectively makes alice an admin.
+ when(ozoneManager.isAdmin(ugiAlice)).thenReturn(true);
+
+ // 1. CreateTenantRequest: Create tenant "finance".
+ long txLogIndex = 1;
+ // Run preExecute
+ OMTenantCreateRequest omTenantCreateRequest =
+ new OMTenantCreateRequest(
+ new OMTenantCreateRequest(
+ createTenantRequest(TENANT_NAME)
+ ).preExecute(ozoneManager)
+ );
+ // Run validateAndUpdateCache
+ OMClientResponse omClientResponse =
+ omTenantCreateRequest.validateAndUpdateCache(ozoneManager,
+ txLogIndex, ozoneManagerDoubleBufferHelper);
+ // Check response type and cast
+ Assert.assertTrue(omClientResponse instanceof OMTenantCreateResponse);
+ final OMTenantCreateResponse omTenantCreateResponse =
+ (OMTenantCreateResponse) omClientResponse;
+ // Check response
+ Assert.assertTrue(omTenantCreateResponse.getOMResponse().getSuccess());
+ Assert.assertEquals(TENANT_NAME,
+ omTenantCreateResponse.getOmDBTenantInfo().getTenantName());
+
+
+ // 2. AssignUserToTenantRequest: Assign "[email protected]" to "finance".
+ ++txLogIndex;
+ // Run preExecute
+ OMAssignUserToTenantRequest omAssignUserToTenantRequest =
+ new OMAssignUserToTenantRequest(
+ new OMAssignUserToTenantRequest(
+ assignUserToTenantRequest(TENANT_NAME, USER_BOB, ACCESS_ID_BOB)
+ ).preExecute(ozoneManager)
+ );
+
+ // Run validateAndUpdateCache
+ omClientResponse =
+ omAssignUserToTenantRequest.validateAndUpdateCache(ozoneManager,
+ txLogIndex, ozoneManagerDoubleBufferHelper);
+
+ // Check response type and cast
+ Assert.assertTrue(omClientResponse instanceof
OMAssignUserToTenantResponse);
+ final OMAssignUserToTenantResponse omAssignUserToTenantResponse =
+ (OMAssignUserToTenantResponse) omClientResponse;
+
+ // Check response
+ Assert.assertTrue(omAssignUserToTenantResponse.getOMResponse()
+ .getSuccess());
+ Assert.assertTrue(omAssignUserToTenantResponse.getOMResponse()
+ .getAssignUserToTenantResponse().getSuccess());
+ final OmDBAccessIdInfo omDBAccessIdInfo =
+ omAssignUserToTenantResponse.getOmDBAccessIdInfo();
+ Assert.assertNotNull(omDBAccessIdInfo);
+
+
+ // 3. S3GetSecretRequest: Get secret of "[email protected]" (as an admin).
+ ++txLogIndex;
+
+ // Run preExecute
+ S3GetSecretRequest s3GetSecretRequest =
+ new S3GetSecretRequest(
+ new S3GetSecretRequest(
+ s3GetSecretRequest(ACCESS_ID_BOB)
+ ).preExecute(ozoneManager)
+ );
+
+ // Run validateAndUpdateCache
+ omClientResponse =
+ s3GetSecretRequest.validateAndUpdateCache(ozoneManager,
+ txLogIndex, ozoneManagerDoubleBufferHelper);
+
+ // Check response type and cast
+ Assert.assertTrue(omClientResponse instanceof S3GetSecretResponse);
+ final S3GetSecretResponse s3GetSecretResponse =
+ (S3GetSecretResponse) omClientResponse;
+
+ // Check response
+ Assert.assertTrue(s3GetSecretResponse.getOMResponse().getSuccess());
+ /*
+ getS3SecretValue() should be null in this case because
+ the entry is already inserted to DB in the previous request.
+ The entry will get overwritten if it isn't null.
+ See {@link S3GetSecretResponse#addToDBBatch}.
+ */
+ Assert.assertNull(s3GetSecretResponse.getS3SecretValue());
+ // The secret retrieved should be the same as previous response's.
+ final GetS3SecretResponse getS3SecretResponse =
+ s3GetSecretResponse.getOMResponse().getGetS3SecretResponse();
+ final S3Secret s3Secret = getS3SecretResponse.getS3Secret();
+ Assert.assertEquals(ACCESS_ID_BOB, s3Secret.getKerberosID());
+ Assert.assertEquals(
+ omDBAccessIdInfo.getSharedSecret(), s3Secret.getAwsSecret());
+ }
+}
diff --git
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/s3/GetS3SecretHandler.java
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/s3/GetS3SecretHandler.java
index df58eea..aa4d893 100644
---
a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/s3/GetS3SecretHandler.java
+++
b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/s3/GetS3SecretHandler.java
@@ -35,8 +35,8 @@ import picocli.CommandLine.Option;
public class GetS3SecretHandler extends S3Handler {
@Option(names = "-u",
- description = "Specify the user name to perform the operation on "
- + "(admins only)'")
+ description = "Specify the user to perform the operation on "
+ + "(Admins only)'")
private String username;
@Option(names = "-e",
@@ -58,8 +58,10 @@ public class GetS3SecretHandler extends S3Handler {
final S3SecretValue secret = client.getObjectStore().getS3Secret(username);
if (export) {
- out().println("export AWS_ACCESS_KEY_ID=" + secret.getAwsAccessKey());
- out().println("export AWS_SECRET_ACCESS_KEY=" + secret.getAwsSecret());
+ out().println("export AWS_ACCESS_KEY_ID='" +
+ secret.getAwsAccessKey() + "'");
+ out().println("export AWS_SECRET_ACCESS_KEY='" +
+ secret.getAwsSecret() + "'");
} else {
out().println(secret);
}
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]