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 681971867d73..12398dd644c3 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 @@ -33,11 +33,14 @@ import org.apache.hadoop.ozone.OzoneAcl; import org.apache.hadoop.ozone.client.protocol.ClientProtocol; import org.apache.hadoop.ozone.om.exceptions.OMException; +import org.apache.hadoop.ozone.om.helpers.DeleteTenantInfo; +import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs; import org.apache.hadoop.ozone.om.helpers.S3SecretValue; +import org.apache.hadoop.ozone.om.helpers.S3VolumeContext; import org.apache.hadoop.ozone.om.helpers.TenantInfoList; import org.apache.hadoop.ozone.om.helpers.TenantUserInfoValue; import org.apache.hadoop.ozone.om.helpers.TenantUserList; -import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteTenantResponse; +import org.apache.hadoop.ozone.om.protocol.S3Auth; import org.apache.hadoop.ozone.security.OzoneTokenIdentifier; import org.apache.hadoop.ozone.security.acl.OzoneObj; import org.apache.hadoop.security.UserGroupInformation; @@ -45,6 +48,8 @@ import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Strings; import org.apache.hadoop.security.token.Token; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * ObjectStore class is responsible for the client operations that can be @@ -52,6 +57,10 @@ */ public class ObjectStore { + private static final Logger LOG = + LoggerFactory.getLogger(ObjectStore.class); + + private final ConfigurationSource conf; /** * The proxy used for connecting to the cluster and perform * client operations. @@ -71,6 +80,7 @@ public class ObjectStore { * @param proxy ClientProtocol proxy. */ public ObjectStore(ConfigurationSource conf, ClientProtocol proxy) { + this.conf = conf; this.proxy = TracingUtil.createProxy(proxy, ClientProtocol.class, conf); this.listCacheSize = HddsClientUtils.getListCacheSize(conf); defaultS3Volume = HddsClientUtils.getDefaultS3VolumeName(conf); @@ -79,7 +89,7 @@ public ObjectStore(ConfigurationSource conf, ClientProtocol proxy) { @VisibleForTesting protected ObjectStore() { // For the unit test - OzoneConfiguration conf = new OzoneConfiguration(); + this.conf = new OzoneConfiguration(); proxy = null; defaultS3Volume = HddsClientUtils.getDefaultS3VolumeName(conf); } @@ -154,7 +164,25 @@ public OzoneVolume getVolume(String volumeName) throws IOException { } public OzoneVolume getS3Volume() throws IOException { - return proxy.getS3VolumeDetails(); + final S3VolumeContext resp = proxy.getS3VolumeContext(); + + S3Auth s3Auth = proxy.getThreadLocalS3Auth(); + // Update user principal if needed to be used for KMS client + if (s3Auth != null) { + // Update userPrincipal field with the value returned from OM. So that + // in multi-tenancy, KMS client can use the correct identity + // (instead of using accessId) to communicate with KMS. + LOG.debug("Updating S3Auth.userPrincipal to {}", resp.getUserPrincipal()); + s3Auth.setUserPrincipal(resp.getUserPrincipal()); + proxy.setTheadLocalS3Auth(s3Auth); + } + + OmVolumeArgs volume = resp.getOmVolumeArgs(); + return proxy.buildOzoneVolume(volume); + } + + public S3VolumeContext getS3VolumeContext() throws IOException { + return proxy.getS3VolumeContext(); } public S3SecretValue getS3Secret(String kerberosID) throws IOException { @@ -207,8 +235,9 @@ public void createTenant(String tenantId, TenantArgs tenantArgs) * Delete a tenant. * @param tenantId tenant name. * @throws IOException + * @return DeleteTenantInfo */ - public DeleteTenantResponse deleteTenant(String tenantId) throws IOException { + public DeleteTenantInfo deleteTenant(String tenantId) throws IOException { return proxy.deleteTenant(tenantId); } 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 639a34095225..2602fd6e2414 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 @@ -43,17 +43,19 @@ 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.DeleteTenantInfo; import org.apache.hadoop.ozone.om.helpers.OmMultipartInfo; import org.apache.hadoop.ozone.om.helpers.OmMultipartUploadCompleteInfo; +import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs; import org.apache.hadoop.ozone.om.helpers.OzoneFileStatus; import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo; import org.apache.hadoop.ozone.om.helpers.S3SecretValue; +import org.apache.hadoop.ozone.om.helpers.S3VolumeContext; import org.apache.hadoop.ozone.om.helpers.TenantInfoList; import org.apache.hadoop.ozone.om.helpers.TenantUserInfoValue; import org.apache.hadoop.ozone.om.helpers.TenantUserList; import org.apache.hadoop.ozone.om.protocol.OzoneManagerProtocol; import org.apache.hadoop.ozone.om.protocol.S3Auth; -import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteTenantResponse; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRoleInfo; import org.apache.hadoop.ozone.security.OzoneTokenIdentifier; import org.apache.hadoop.ozone.security.acl.OzoneObj; @@ -124,11 +126,13 @@ OzoneVolume getVolumeDetails(String volumeName) throws IOException; /** - * @return The {@link OzoneVolume} that should be used to for this S3 - * request based on its access ID. + * @return Raw GetS3VolumeContextResponse. + * S3Auth won't be updated with actual userPrincipal by this call. * @throws IOException */ - OzoneVolume getS3VolumeDetails() throws IOException; + S3VolumeContext getS3VolumeContext() throws IOException; + + OzoneVolume buildOzoneVolume(OmVolumeArgs volume); /** * Checks if a Volume exists and the user with a role specified has access @@ -609,8 +613,9 @@ S3SecretValue setS3Secret(String accessId, String secretKey) * Delete a tenant. * @param tenantId tenant name. * @throws IOException + * @return DeleteTenantInfo */ - DeleteTenantResponse deleteTenant(String tenantId) throws IOException; + DeleteTenantInfo deleteTenant(String tenantId) throws IOException; /** * Assign a user to a tenant. 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 831fbd9a95ea..5d5e576decff 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 @@ -84,6 +84,7 @@ import org.apache.hadoop.ozone.om.OMConfigKeys; import org.apache.hadoop.ozone.om.exceptions.OMException; import org.apache.hadoop.ozone.om.helpers.BucketEncryptionKeyInfo; +import org.apache.hadoop.ozone.om.helpers.DeleteTenantInfo; import org.apache.hadoop.ozone.om.helpers.OmBucketArgs; import org.apache.hadoop.ozone.om.helpers.OmBucketInfo; import org.apache.hadoop.ozone.om.helpers.OmDeleteKeys; @@ -104,6 +105,7 @@ import org.apache.hadoop.ozone.om.helpers.OzoneFileStatus; import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo; import org.apache.hadoop.ozone.om.helpers.S3SecretValue; +import org.apache.hadoop.ozone.om.helpers.S3VolumeContext; import org.apache.hadoop.ozone.om.helpers.ServiceInfo; import org.apache.hadoop.ozone.om.helpers.ServiceInfoEx; import org.apache.hadoop.ozone.om.helpers.TenantInfoList; @@ -115,7 +117,6 @@ import org.apache.hadoop.ozone.om.protocolPB.OmTransportFactory; import org.apache.hadoop.ozone.om.protocolPB.OzoneManagerClientProtocol; import org.apache.hadoop.ozone.om.protocolPB.OzoneManagerProtocolClientSideTranslatorPB; -import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteTenantResponse; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRoleInfo; import org.apache.hadoop.ozone.security.GDPRSymmetricKey; import org.apache.hadoop.ozone.security.OzoneTokenIdentifier; @@ -437,12 +438,11 @@ public OzoneVolume getVolumeDetails(String volumeName) } @Override - public OzoneVolume getS3VolumeDetails() throws IOException { - OmVolumeArgs volume = ozoneManagerClient.getS3Volume(); - return buildOzoneVolume(volume); + public S3VolumeContext getS3VolumeContext() throws IOException { + return ozoneManagerClient.getS3VolumeContext(); } - private OzoneVolume buildOzoneVolume(OmVolumeArgs volume) { + public OzoneVolume buildOzoneVolume(OmVolumeArgs volume) { return new OzoneVolume( conf, this, @@ -770,7 +770,7 @@ public void createTenant(String tenantId, TenantArgs tenantArgs) * {@inheritDoc} */ @Override - public DeleteTenantResponse deleteTenant(String tenantId) throws IOException { + public DeleteTenantInfo deleteTenant(String tenantId) throws IOException { Preconditions.checkArgument(Strings.isNotBlank(tenantId), "tenantId cannot be null or empty."); return ozoneManagerClient.deleteTenant(tenantId); @@ -1062,8 +1062,10 @@ private KeyProvider.KeyVersion getDEK(FileEncryptionInfo feInfo) UserGroupInformation loginUser = UserGroupInformation.getLoginUser(); UserGroupInformation proxyUser; if (getThreadLocalS3Auth() != null) { + String userPrincipal = getThreadLocalS3Auth().getUserPrincipal(); + Preconditions.checkNotNull(userPrincipal); UserGroupInformation s3gUGI = UserGroupInformation.createRemoteUser( - getThreadLocalS3Auth().getAccessID()); + userPrincipal); proxyUser = UserGroupInformation.createProxyUser( s3gUGI.getShortUserName(), loginUser); decrypted = proxyUser.doAs( 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 19fb44cf2bc5..be81b0ad96d0 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 @@ -263,7 +263,7 @@ public static boolean isReadOnly( case ListMultipartUploads: case FinalizeUpgradeProgress: case PrepareStatus: - case GetS3Volume: + case GetS3VolumeContext: case ListTenant: case TenantGetUserInfo: case TenantListUser: diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/DeleteTenantInfo.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/DeleteTenantInfo.java new file mode 100644 index 000000000000..b38c3cd4c5e9 --- /dev/null +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/DeleteTenantInfo.java @@ -0,0 +1,91 @@ +/* + * 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 org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteTenantResponse; + +/** + * A class that encapsulates DeleteTenantResponse protobuf message. + */ +public class DeleteTenantInfo { + + /** + * Volume name associated to the deleted tenant. + */ + private final String volumeName; + + /** + * Reference count remaining of the volume associated to the deleted tenant. + */ + private final long volRefCount; + + public DeleteTenantInfo(String volumeName, long volRefCount) { + this.volumeName = volumeName; + this.volRefCount = volRefCount; + } + + public String getVolumeName() { + return volumeName; + } + + public long getVolRefCount() { + return volRefCount; + } + + public static DeleteTenantInfo fromProtobuf(DeleteTenantResponse resp) { + return new DeleteTenantInfo(resp.getVolumeName(), resp.getVolRefCount()); + } + + public DeleteTenantResponse getProtobuf() { + return DeleteTenantResponse.newBuilder() + .setVolumeName(volumeName) + .setVolRefCount(volRefCount) + .build(); + } + + public static DeleteTenantInfo.Builder newBuilder() { + return new DeleteTenantInfo.Builder(); + } + + /** + * Builder for TenantDeleted. + */ + @SuppressWarnings("checkstyle:hiddenfield") + public static final class Builder { + private String volumeName; + private long volRefCount; + + private Builder() { + } + + public Builder setVolumeName(String volumeName) { + this.volumeName = volumeName; + return this; + } + + public Builder setVolRefCount(long volRefCount) { + this.volRefCount = volRefCount; + return this; + } + + public DeleteTenantInfo build() { + return new DeleteTenantInfo(volumeName, volRefCount); + } + } +} diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/S3VolumeContext.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/S3VolumeContext.java new file mode 100644 index 000000000000..dbbc3544765d --- /dev/null +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/helpers/S3VolumeContext.java @@ -0,0 +1,94 @@ +/* + * 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 org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetS3VolumeContextResponse; + +/** + * A class that encapsulates GetS3VolumeContextResponse protobuf message. + */ +public class S3VolumeContext { + + /** + * Various volume arguments. + */ + private final OmVolumeArgs omVolumeArgs; + + /** + * Piggybacked username (principal) response. + * To be used for client-side operations involving KMS like getDEK(). + */ + private final String userPrincipal; + + public S3VolumeContext(OmVolumeArgs omVolumeArgs, String userPrincipal) { + this.omVolumeArgs = omVolumeArgs; + this.userPrincipal = userPrincipal; + } + + public OmVolumeArgs getOmVolumeArgs() { + return omVolumeArgs; + } + + public String getUserPrincipal() { + return userPrincipal; + } + + public static S3VolumeContext fromProtobuf(GetS3VolumeContextResponse resp) { + return new S3VolumeContext( + OmVolumeArgs.getFromProtobuf(resp.getVolumeInfo()), + resp.getUserPrincipal()); + } + + public GetS3VolumeContextResponse getProtobuf() { + return GetS3VolumeContextResponse.newBuilder() + .setVolumeInfo(omVolumeArgs.getProtobuf()) + .setUserPrincipal(userPrincipal) + .build(); + } + + public static S3VolumeContext.Builder newBuilder() { + return new S3VolumeContext.Builder(); + } + + /** + * Builder for S3VolumeContext. + */ + @SuppressWarnings("checkstyle:hiddenfield") + public static final class Builder { + private OmVolumeArgs omVolumeArgs; + private String userPrincipal; + + private Builder() { + } + + public Builder setOmVolumeArgs(OmVolumeArgs omVolumeArgs) { + this.omVolumeArgs = omVolumeArgs; + return this; + } + + public Builder setUserPrincipal(String userPrincipal) { + this.userPrincipal = userPrincipal; + return this; + } + + public S3VolumeContext build() { + return new S3VolumeContext(omVolumeArgs, userPrincipal); + } + } +} 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 b0c35e6943e4..f144d6290890 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 @@ -27,6 +27,7 @@ import org.apache.hadoop.ozone.om.OMConfigKeys; import org.apache.hadoop.ozone.om.exceptions.OMException; import org.apache.hadoop.ozone.om.helpers.DBUpdates; +import org.apache.hadoop.ozone.om.helpers.DeleteTenantInfo; import org.apache.hadoop.ozone.om.helpers.OmBucketArgs; import org.apache.hadoop.ozone.om.helpers.OmBucketInfo; import org.apache.hadoop.ozone.om.helpers.OmDeleteKeys; @@ -46,13 +47,13 @@ import org.apache.hadoop.ozone.om.helpers.OzoneFileStatus; import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo; import org.apache.hadoop.ozone.om.helpers.S3SecretValue; +import org.apache.hadoop.ozone.om.helpers.S3VolumeContext; import org.apache.hadoop.ozone.om.helpers.ServiceInfo; import org.apache.hadoop.ozone.om.helpers.ServiceInfoEx; import org.apache.hadoop.ozone.om.helpers.TenantInfoList; import org.apache.hadoop.ozone.om.helpers.TenantUserInfoValue; import org.apache.hadoop.ozone.om.helpers.TenantUserList; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos; -import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteTenantResponse; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OzoneAclInfo; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PrepareStatusResponse; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PrepareStatusResponse.PrepareStatus; @@ -595,7 +596,7 @@ default void createTenant(OmTenantArgs omTenantArgs) throws IOException { * @return DeleteTenantResponse * @throws IOException */ - default DeleteTenantResponse deleteTenant(String tenantId) + default DeleteTenantInfo deleteTenant(String tenantId) throws IOException { throw new UnsupportedOperationException("OzoneManager does not require " + "this to be implemented, as write requests use a new approach"); @@ -617,7 +618,7 @@ default S3SecretValue tenantAssignUserAccessId(String username, "this to be implemented, as write requests use a new approach"); } - OmVolumeArgs getS3Volume() throws IOException; + S3VolumeContext getS3VolumeContext() throws IOException; /** * Revoke user accessId to a tenant. diff --git a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/S3Auth.java b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/S3Auth.java index aae81adf6259..932ff49e8448 100644 --- a/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/S3Auth.java +++ b/hadoop-ozone/common/src/main/java/org/apache/hadoop/ozone/om/protocol/S3Auth.java @@ -25,13 +25,19 @@ public class S3Auth { private String signature; private String accessID; public static final String S3_AUTH_CHECK = "ozone.s3.auth.check"; + // User principal to be used for KMS encryption and decryption + private String userPrincipal; public S3Auth(final String stringToSign, - final String signature, final String accessID) { - this.accessID = accessID; + final String signature, + final String accessID, + final String userPrincipal) { this.stringToSign = stringToSign; this.signature = signature; + this.accessID = accessID; + this.userPrincipal = userPrincipal; } + public String getStringTosSign() { return stringToSign; } @@ -43,4 +49,12 @@ public String getSignature() { public String getAccessID() { return accessID; } + + public String getUserPrincipal() { + return userPrincipal; + } + + public void setUserPrincipal(String userPrincipal) { + this.userPrincipal = userPrincipal; + } } 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 40dccb605652..3b161d75d820 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 @@ -34,6 +34,7 @@ import org.apache.hadoop.ozone.OzoneAcl; import org.apache.hadoop.ozone.om.exceptions.OMException; import org.apache.hadoop.ozone.om.helpers.DBUpdates; +import org.apache.hadoop.ozone.om.helpers.DeleteTenantInfo; import org.apache.hadoop.ozone.om.helpers.KeyValueUtil; import org.apache.hadoop.ozone.om.helpers.OmBucketArgs; import org.apache.hadoop.ozone.om.helpers.OmBucketInfo; @@ -55,6 +56,7 @@ import org.apache.hadoop.ozone.om.helpers.OzoneFileStatus; import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo; import org.apache.hadoop.ozone.om.helpers.S3SecretValue; +import org.apache.hadoop.ozone.om.helpers.S3VolumeContext; import org.apache.hadoop.ozone.om.helpers.ServiceInfo; import org.apache.hadoop.ozone.om.helpers.ServiceInfoEx; import org.apache.hadoop.ozone.om.helpers.TenantInfoList; @@ -986,7 +988,7 @@ public void createTenant(OmTenantArgs omTenantArgs) throws IOException { } @Override - public DeleteTenantResponse deleteTenant(String tenantId) throws IOException { + public DeleteTenantInfo deleteTenant(String tenantId) throws IOException { final DeleteTenantRequest request = DeleteTenantRequest.newBuilder() .setTenantId(tenantId) .build(); @@ -994,8 +996,9 @@ public DeleteTenantResponse deleteTenant(String tenantId) throws IOException { .setDeleteTenantRequest(request) .build(); final OMResponse omResponse = submitRequest(omRequest); - - return handleError(omResponse).getDeleteTenantResponse(); + final DeleteTenantResponse resp = + handleError(omResponse).getDeleteTenantResponse(); + return DeleteTenantInfo.fromProtobuf(resp); } /** @@ -1124,17 +1127,17 @@ public TenantUserList listUsersInTenant(String tenantName, String prefix) } @Override - public OmVolumeArgs getS3Volume() throws IOException { - final GetS3VolumeRequest request = GetS3VolumeRequest.newBuilder() + public S3VolumeContext getS3VolumeContext() throws IOException { + final GetS3VolumeContextRequest request = GetS3VolumeContextRequest + .newBuilder() .build(); - final OMRequest omRequest = createOMRequest(Type.GetS3Volume) - .setGetS3VolumeRequest(request) + final OMRequest omRequest = createOMRequest(Type.GetS3VolumeContext) + .setGetS3VolumeContextRequest(request) .build(); final OMResponse omResponse = submitRequest(omRequest); - final GetS3VolumeResponse resp = handleError(omResponse) - .getGetS3VolumeResponse(); - - return OmVolumeArgs.getFromProtobuf(resp.getVolumeInfo()); + final GetS3VolumeContextResponse resp = + handleError(omResponse).getGetS3VolumeContextResponse(); + return S3VolumeContext.fromProtobuf(resp); } /** diff --git a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/multitenant/TestMultiTenantVolume.java b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/multitenant/TestMultiTenantVolume.java index ee2d9ab197be..359120e38582 100644 --- a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/multitenant/TestMultiTenantVolume.java +++ b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/multitenant/TestMultiTenantVolume.java @@ -138,7 +138,9 @@ private ObjectStore getStoreForAccessID(String accessID) throws Exception { // Manually construct an object store instead of using the cluster // provided one so we can specify the access ID. RpcClient client = new RpcClient(conf, null); - client.setTheadLocalS3Auth(new S3Auth("unused1", "unused2", accessID)); + // userPrincipal is set to be the same as accessId for the test + client.setTheadLocalS3Auth( + new S3Auth("unused1", "unused2", accessID, accessID)); return new ObjectStore(conf, client); } } diff --git a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto index 7573b99a984f..77c5376bf315 100644 --- a/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto +++ b/hadoop-ozone/interface-client/src/main/proto/OmClientProtocol.proto @@ -114,7 +114,7 @@ enum Type { TenantAssignAdmin = 102; TenantRevokeAdmin = 103; - GetS3Volume = 104; + GetS3VolumeContext = 104; TenantListUser = 105; SetS3Secret = 106; @@ -214,7 +214,7 @@ message OMRequest { optional TenantAssignAdminRequest TenantAssignAdminRequest = 102; optional TenantRevokeAdminRequest TenantRevokeAdminRequest = 103; - optional GetS3VolumeRequest getS3VolumeRequest = 104; + optional GetS3VolumeContextRequest getS3VolumeContextRequest = 104; optional TenantListUserRequest tenantListUserRequest = 105; optional SetS3SecretRequest SetS3SecretRequest = 106; @@ -307,7 +307,7 @@ message OMResponse { optional TenantAssignAdminResponse TenantAssignAdminResponse = 102; optional TenantRevokeAdminResponse TenantRevokeAdminResponse = 103; - optional GetS3VolumeResponse getS3VolumeResponse = 104; + optional GetS3VolumeContextResponse getS3VolumeContextResponse = 104; optional TenantListUserResponse tenantListUserResponse = 105; optional SetS3SecretResponse SetS3SecretResponse = 106; @@ -1504,7 +1504,7 @@ message TenantRevokeAdminRequest { optional string tenantName = 2; } -message GetS3VolumeRequest { +message GetS3VolumeContextRequest { } @@ -1541,8 +1541,10 @@ message OmDBAccessInfo { optional bool isDelegatedAdmin = 4; } -message GetS3VolumeResponse { +message GetS3VolumeContextResponse { optional VolumeInfo volumeInfo = 1; + // Piggybacked username (principal) response to be used for KMS client operations + optional string userPrincipal = 2; } /** diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneAclUtils.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneAclUtils.java index 91eeaebc7516..5257279bb3ca 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneAclUtils.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/OzoneAclUtils.java @@ -47,7 +47,8 @@ public static void setOMMultiTenantManager( * If the access ID does not belong to a tenant, the access ID is returned * as is to be used as the principal. */ - public static String principalToAccessID(String accessID) throws IOException { + public static String accessIdToUserPrincipal(String accessID) + throws IOException { String principal = multiTenantManager.getUserNameGivenAccessId(accessID); if (principal == null) { principal = accessID; 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 409212a0edf5..7d120e1f248c 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 @@ -126,6 +126,7 @@ import org.apache.hadoop.ozone.om.helpers.OmVolumeArgs; import org.apache.hadoop.ozone.om.helpers.OzoneFileStatus; import org.apache.hadoop.ozone.om.helpers.RepeatedOmKeyInfo; +import org.apache.hadoop.ozone.om.helpers.S3VolumeContext; import org.apache.hadoop.ozone.om.helpers.ServiceInfo; import org.apache.hadoop.ozone.om.helpers.ServiceInfoEx; import org.apache.hadoop.ozone.om.helpers.TenantInfoList; @@ -2233,7 +2234,7 @@ private void checkAcls(ResourceType resType, StoreType store, UserGroupInformation user; if (getS3Auth() != null) { String principal = - OzoneAclUtils.principalToAccessID(getS3Auth().getAccessId()); + OzoneAclUtils.accessIdToUserPrincipal(getS3Auth().getAccessId()); user = UserGroupInformation.createRemoteUser(principal); } else { user = ProtobufRpcEngine.Server.getRemoteUser(); @@ -3077,12 +3078,13 @@ public TenantUserList listUsersInTenant(String tenantId, String prefix) } @Override - public OmVolumeArgs getS3Volume() throws IOException { + public S3VolumeContext getS3VolumeContext() throws IOException { // Unless the OM request contains S3 authentication info with an access // ID that corresponds to a tenant volume, the request will be directed // to the default S3 volume. String s3Volume = HddsClientUtils.getDefaultS3VolumeName(configuration); S3Authentication s3Auth = getS3Auth(); + String userPrincipal = Server.getRemoteUser().getShortUserName(); if (s3Auth != null) { String accessID = s3Auth.getAccessId(); @@ -3110,6 +3112,9 @@ public OmVolumeArgs getS3Volume() throws IOException { "tenant {} is directed to the volume {}.", accessID, tenantId, s3Volume); } + + // Inject user name to the response to be used for KMS on the client + userPrincipal = OzoneAclUtils.accessIdToUserPrincipal(accessID); } else if (LOG.isDebugEnabled()) { LOG.debug("No tenant found for access ID {}. Directing " + "requests to default s3 volume {}.", accessID, s3Volume); @@ -3123,8 +3128,12 @@ public OmVolumeArgs getS3Volume() throws IOException { s3Volume); } - // This call performs acl checks and checks volume existence. - return getVolumeInfo(s3Volume); + // getVolumeInfo() performs acl checks and checks volume existence. + final S3VolumeContext.Builder s3VolumeContext = S3VolumeContext.newBuilder() + .setOmVolumeArgs(getVolumeInfo(s3Volume)) + .setUserPrincipal(userPrincipal); + + return s3VolumeContext.build(); } @Override @@ -3862,7 +3871,8 @@ public ResolvedBucket resolveBucketLink(Pair requested) if (getS3Auth() != null) { ugi = UserGroupInformation .createRemoteUser( - OzoneAclUtils.principalToAccessID(getS3Auth().getAccessId())); + OzoneAclUtils.accessIdToUserPrincipal( + getS3Auth().getAccessId())); } InetAddress remoteIp = Server.getRemoteIp(); resolved = resolveBucketLink(requested, new HashSet<>(), @@ -3960,7 +3970,7 @@ private void addS3GVolumeToDB() throws IOException { // Add volume and user info to DB and cache. - OmVolumeArgs omVolumeArgs = createS3VolumeInfo(s3VolumeName, objectID); + OmVolumeArgs omVolumeArgs = createS3VolumeContext(s3VolumeName, objectID); String dbUserKey = metadataManager.getUserKey(userName); PersistedUserVolumeInfo userVolumeInfo = @@ -3994,7 +4004,7 @@ private void addS3GVolumeToDB() throws IOException { } } - private OmVolumeArgs createS3VolumeInfo(String s3Volume, + private OmVolumeArgs createS3VolumeContext(String s3Volume, long objectID) throws IOException { String userName = UserGroupInformation.getCurrentUser().getShortUserName(); long time = Time.now(); diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/OMClientRequest.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/OMClientRequest.java index e430665be131..8d1a8f1bae84 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/OMClientRequest.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/OMClientRequest.java @@ -141,7 +141,7 @@ public OzoneManagerProtocolProtos.UserInfo getUserInfo() throws IOException { // If S3 Authentication is set, determine user based on access ID. if (omRequest.hasS3Authentication()) { - String principal = OzoneAclUtils.principalToAccessID( + String principal = OzoneAclUtils.accessIdToUserPrincipal( omRequest.getS3Authentication().getAccessId()); userInfo.setUserName(principal); } else if (user != null) { diff --git a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java index 820686b9eaf3..324c599cb444 100644 --- a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java +++ b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/protocolPB/OzoneManagerRequestHandler.java @@ -80,7 +80,7 @@ import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.PrepareStatusResponse; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ServiceListRequest; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.ServiceListResponse; -import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetS3VolumeResponse; +import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.GetS3VolumeContextResponse; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.TenantGetUserInfoRequest; import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.TenantGetUserInfoResponse; @@ -227,9 +227,10 @@ public OMResponse handleReadRequest(OMRequest request) { PrepareStatusResponse prepareStatusResponse = getPrepareStatus(); responseBuilder.setPrepareStatusResponse(prepareStatusResponse); break; - case GetS3Volume: - GetS3VolumeResponse s3VolumeResponse = getS3Volume(); - responseBuilder.setGetS3VolumeResponse(s3VolumeResponse); + case GetS3VolumeContext: + GetS3VolumeContextResponse s3VolumeContextResponse = + getS3VolumeContext(); + responseBuilder.setGetS3VolumeContextResponse(s3VolumeContextResponse); break; case TenantGetUserInfo: TenantGetUserInfoResponse getUserInfoResponse = tenantGetUserInfo( @@ -708,12 +709,9 @@ private PrepareStatusResponse getPrepareStatus() { .setCurrentTxnIndex(prepareState.getIndex()).build(); } - private GetS3VolumeResponse getS3Volume() + private GetS3VolumeContextResponse getS3VolumeContext() throws IOException { - OmVolumeArgs s3VolArgs = impl.getS3Volume(); - return GetS3VolumeResponse.newBuilder() - .setVolumeInfo(s3VolArgs.getProtobuf()) - .build(); + return impl.getS3VolumeContext().getProtobuf(); } public OzoneManager getOzoneManager() { diff --git a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/OzoneClientProducer.java b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/OzoneClientProducer.java index b81b0aa2f526..a6897fd5291a 100644 --- a/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/OzoneClientProducer.java +++ b/hadoop-ozone/s3gateway/src/main/java/org/apache/hadoop/ozone/s3/OzoneClientProducer.java @@ -91,9 +91,11 @@ public S3Auth getSignature() { String awsAccessId = signatureInfo.getAwsAccessId(); validateAccessId(awsAccessId); + // Note: userPrincipal is initialized to be the same value as accessId, + // could be updated later in RpcClient#getS3Volume return new S3Auth(stringToSign, signatureInfo.getSignature(), - awsAccessId); + awsAccessId, awsAccessId); } catch (OS3Exception ex) { LOG.debug("Error during Client Creation: ", ex); throw wrapOS3Exception(ex); diff --git a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/tenant/TenantAssignAdminHandler.java b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/tenant/TenantAssignAdminHandler.java index 2029dec89c77..1de3ec1206c4 100644 --- a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/tenant/TenantAssignAdminHandler.java +++ b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/tenant/TenantAssignAdminHandler.java @@ -59,11 +59,11 @@ protected void execute(OzoneClient client, OzoneAddress address) { objStore.tenantAssignAdmin(accessId, tenantId, delegated); // TODO: Make tenantAssignAdmin return accessId, tenantName, user later. err().println("Assigned admin to '" + accessId + - (tenantId != null ? "' in tenant '" + tenantId + "'" : "")); + (tenantId != null ? "' in tenant '" + tenantId : "") + "'"); } catch (IOException e) { err().println("Failed to assign admin to '" + accessId + - (tenantId != null ? "' in tenant '" + tenantId + "'" : "") + - ": " + e.getMessage()); + (tenantId != null ? "' in tenant '" + tenantId : "") + "': " + + e.getMessage()); if (e instanceof OMException) { final OMException omEx = (OMException) e; // Don't bother continuing the loop if current user isn't Ozone admin diff --git a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/tenant/TenantDeleteHandler.java b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/tenant/TenantDeleteHandler.java index 1f8067da5342..1a88105ca827 100644 --- a/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/tenant/TenantDeleteHandler.java +++ b/hadoop-ozone/tools/src/main/java/org/apache/hadoop/ozone/shell/tenant/TenantDeleteHandler.java @@ -18,7 +18,7 @@ package org.apache.hadoop.ozone.shell.tenant; import org.apache.hadoop.ozone.client.OzoneClient; -import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.DeleteTenantResponse; +import org.apache.hadoop.ozone.om.helpers.DeleteTenantInfo; import org.apache.hadoop.ozone.shell.OzoneAddress; import picocli.CommandLine; @@ -39,7 +39,7 @@ public class TenantDeleteHandler extends TenantHandler { protected void execute(OzoneClient client, OzoneAddress address) throws IOException { try { - final DeleteTenantResponse resp = + final DeleteTenantInfo resp = client.getObjectStore().deleteTenant(tenantId); out().println("Deleted tenant '" + tenantId + "'."); long volumeRefCount = resp.getVolRefCount();