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]

Reply via email to