This is an automated email from the ASF dual-hosted git repository.
smengcl pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ozone.git
The following commit(s) were added to refs/heads/master by this push:
new e655551ef59 Improve EchoRPC request handling in OM.
e655551ef59 is described below
commit e655551ef594255e6e6e1e74aafee9b37be9b09e
Author: Siyao Meng <[email protected]>
AuthorDate: Tue Oct 13 21:41:58 2026 -0700
Improve EchoRPC request handling in OM.
---
.../ozone/om/TestOMAdminRpcAuthorization.java | 54 ++++++++++++++++++++++
.../om/request/util/OMEchoRPCWriteRequest.java | 17 +++++++
.../protocolPB/OzoneManagerRequestHandler.java | 9 +++-
3 files changed, 79 insertions(+), 1 deletion(-)
diff --git
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOMAdminRpcAuthorization.java
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOMAdminRpcAuthorization.java
index ceb904b4471..f84636ed842 100644
---
a/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOMAdminRpcAuthorization.java
+++
b/hadoop-ozone/integration-test/src/test/java/org/apache/hadoop/ozone/om/TestOMAdminRpcAuthorization.java
@@ -34,17 +34,26 @@
import org.apache.hadoop.hdds.conf.OzoneConfiguration;
import org.apache.hadoop.hdds.security.symmetric.ManagedSecretKey;
import org.apache.hadoop.hdds.security.symmetric.SecretKeyClient;
+import org.apache.hadoop.ipc_.RPC;
+import org.apache.hadoop.ipc_.Server;
import org.apache.hadoop.ozone.MiniOzoneCluster;
import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.protocol.OMConfiguration;
import org.apache.hadoop.ozone.om.protocolPB.OMAdminProtocolClientSideImpl;
import org.apache.hadoop.ozone.om.protocolPB.OmTransportFactory;
import
org.apache.hadoop.ozone.om.protocolPB.OzoneManagerProtocolClientSideTranslatorPB;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.EchoRPCRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
+import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Status;
+import org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.Type;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.ratis.protocol.ClientId;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
+import org.junit.jupiter.params.ParameterizedTest;
+import org.junit.jupiter.params.provider.ValueSource;
/**
* Tests admin authorization of two OM administrative RPCs that are only ever
driven by admin
@@ -140,4 +149,49 @@ void getOMConfigurationAdminIsAllowed() throws Exception {
OMConfiguration omConfig = getOMConfiguration(admin);
assertFalse(omConfig.getCurrentPeerList().isEmpty());
}
+
+ private static int echoRPC(UserGroupInformation user, boolean writeToRatis)
throws Exception {
+ return user.doAs((PrivilegedExceptionAction<Integer>) () -> {
+ try (OzoneManagerProtocolClientSideTranslatorPB omClient = new
OzoneManagerProtocolClientSideTranslatorPB(
+ OmTransportFactory.create(conf, user, null),
ClientId.randomId().toString())) {
+ return omClient.echoRPCReq(new byte[0], 16,
writeToRatis).getPayload().size();
+ }
+ });
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = {false, true})
+ void echoRPCNonAdminIsDenied(boolean writeToRatis) {
+ UserGroupInformation nonAdmin =
UserGroupInformation.createUserForTesting("nonadmin", new String[] {"users"});
+ OMException ex = assertThrows(OMException.class, () -> echoRPC(nonAdmin,
writeToRatis));
+ assertEquals(OMException.ResultCodes.ACCESS_DENIED, ex.getResult());
+ }
+
+ @ParameterizedTest
+ @ValueSource(booleans = {false, true})
+ void echoRPCAdminIsAllowed(boolean writeToRatis) throws Exception {
+ UserGroupInformation admin =
UserGroupInformation.createUserForTesting("admin", new String[] {"admins"});
+ assertEquals(16, echoRPC(admin, writeToRatis));
+ }
+
+ /** A call without an RPC user, as on the OM gRPC endpoint, must not be
treated as the OM user. */
+ @ParameterizedTest
+ @ValueSource(booleans = {false, true})
+ void echoRPCWithoutRpcUserIsDenied(boolean writeToRatis) throws Exception {
+ OMRequest request = OMRequest.newBuilder()
+ .setCmdType(Type.EchoRPC)
+ .setClientId(ClientId.randomId().toString())
+
.setEchoRPCRequest(EchoRPCRequest.newBuilder().setPayloadSizeResp(16).setReadOnly(!writeToRatis))
+ .build();
+
+ // The call context that OzoneManagerServiceGrpc sets up: a client ID, but
no connection and so no user.
+ Server.getCurCall().set(new Server.Call(1, 1, null, null,
RPC.RpcKind.RPC_PROTOCOL_BUFFER,
+ ClientId.randomId().toByteString().toByteArray()));
+ try {
+ OMResponse response =
cluster.getOzoneManager().getOmServerProtocol().submitRequest(null, request);
+ assertEquals(Status.ACCESS_DENIED, response.getStatus());
+ } finally {
+ Server.getCurCall().remove();
+ }
+ }
}
diff --git
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/util/OMEchoRPCWriteRequest.java
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/util/OMEchoRPCWriteRequest.java
index 13df481a91a..d3d20e953c1 100644
---
a/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/util/OMEchoRPCWriteRequest.java
+++
b/hadoop-ozone/ozone-manager/src/main/java/org/apache/hadoop/ozone/om/request/util/OMEchoRPCWriteRequest.java
@@ -18,7 +18,10 @@
package org.apache.hadoop.ozone.om.request.util;
import com.google.protobuf.ByteString;
+import java.io.IOException;
+import org.apache.hadoop.ipc_.ProtobufRpcEngine;
import org.apache.hadoop.ozone.om.OzoneManager;
+import org.apache.hadoop.ozone.om.exceptions.OMException;
import org.apache.hadoop.ozone.om.execution.flowcontrol.ExecutionContext;
import org.apache.hadoop.ozone.om.request.OMClientRequest;
import org.apache.hadoop.ozone.om.response.OMClientResponse;
@@ -28,6 +31,7 @@
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMRequest;
import
org.apache.hadoop.ozone.protocol.proto.OzoneManagerProtocolProtos.OMResponse;
import org.apache.hadoop.ozone.util.PayloadUtils;
+import org.apache.hadoop.security.UserGroupInformation;
/**
* Handles EchoRPC request (write).
@@ -38,6 +42,19 @@ public OMEchoRPCWriteRequest(OMRequest omRequest) {
super(omRequest);
}
+ @Override
+ public OMRequest preExecute(OzoneManager ozoneManager) throws IOException {
+ final OMRequest request = super.preExecute(ozoneManager);
+ // The caller chooses the size of the response payload, so EchoRPC is
limited to admins.
+ // The user info of the request falls back to the OM user for a call
without an RPC user, so check the RPC user.
+ final UserGroupInformation ugi = ProtobufRpcEngine.Server.getRemoteUser();
+ if (ozoneManager.isAdminAuthorizationEnabled() &&
!ozoneManager.isAdmin(ugi)) {
+ throw new OMException("Access denied for user " + ugi + ". Superuser
privilege is required for EchoRPC.",
+ OMException.ResultCodes.ACCESS_DENIED);
+ }
+ return request;
+ }
+
@Override
public OMClientResponse validateAndUpdateCache(OzoneManager ozoneManager,
ExecutionContext context) {
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 e1795f9dd95..b862bd03662 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
@@ -61,6 +61,7 @@
import org.apache.hadoop.hdds.scm.protocolPB.OzonePBHelper;
import org.apache.hadoop.hdds.utils.FaultInjector;
import org.apache.hadoop.hdds.utils.db.cache.TableCacheUpdateTracker;
+import org.apache.hadoop.ipc_.ProtobufRpcEngine;
import org.apache.hadoop.ozone.ClientVersion;
import org.apache.hadoop.ozone.OzoneAcl;
import org.apache.hadoop.ozone.om.OzoneAclUtils;
@@ -1673,7 +1674,13 @@ public OzoneManager getOzoneManager() {
return impl;
}
- private EchoRPCResponse echoRPC(EchoRPCRequest req) {
+ private EchoRPCResponse echoRPC(EchoRPCRequest req) throws IOException {
+ // The caller chooses the size of the response payload, so EchoRPC is
limited to admins.
+ final UserGroupInformation ugi = ProtobufRpcEngine.Server.getRemoteUser();
+ if (impl.isAdminAuthorizationEnabled() && !impl.isAdmin(ugi)) {
+ throw new OMException("Access denied for user " + ugi + ". Superuser
privilege is required for EchoRPC.",
+ OMException.ResultCodes.ACCESS_DENIED);
+ }
EchoRPCResponse.Builder builder = EchoRPCResponse.newBuilder();
final ByteString payloadBytes =
PayloadUtils.generatePayloadProto2(req.getPayloadSizeResp());
builder.setPayload(payloadBytes);
---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]