summaryrefslogtreecommitdiffstats
path: root/jrt
diff options
context:
space:
mode:
authorBjørn Christian Seime <bjorncs@yahooinc.com>2022-07-19 13:40:00 +0200
committerBjørn Christian Seime <bjorncs@yahooinc.com>2022-07-20 13:56:33 +0200
commitb10026b7f483c0b1a30b78e4bce8b182f6487b08 (patch)
tree923bbe8ed6b7ed54145894000ad4137298454bf6 /jrt
parentaedcb7eaea2ee9f059ff55f819a6b8f91aaa15ae (diff)
Introduce per method request access filtering to JRT
Diffstat (limited to 'jrt')
-rw-r--r--jrt/src/com/yahoo/jrt/ErrorCode.java3
-rw-r--r--jrt/src/com/yahoo/jrt/InvocationServer.java6
-rw-r--r--jrt/src/com/yahoo/jrt/Method.java6
-rw-r--r--jrt/src/com/yahoo/jrt/RequestAccessFilter.java17
-rw-r--r--jrt/tests/com/yahoo/jrt/InvokeErrorTest.java37
5 files changed, 67 insertions, 2 deletions
diff --git a/jrt/src/com/yahoo/jrt/ErrorCode.java b/jrt/src/com/yahoo/jrt/ErrorCode.java
index beaabcea316..8e129cfef98 100644
--- a/jrt/src/com/yahoo/jrt/ErrorCode.java
+++ b/jrt/src/com/yahoo/jrt/ErrorCode.java
@@ -49,4 +49,7 @@ public class ErrorCode
/** Method failed (111) **/
public static final int METHOD_FAILED = 111;
+
+ /** Permission denied (112) **/
+ public static final int PERMISSION_DENIED = 112;
}
diff --git a/jrt/src/com/yahoo/jrt/InvocationServer.java b/jrt/src/com/yahoo/jrt/InvocationServer.java
index 9df92eb20a6..7704c0019ed 100644
--- a/jrt/src/com/yahoo/jrt/InvocationServer.java
+++ b/jrt/src/com/yahoo/jrt/InvocationServer.java
@@ -31,7 +31,11 @@ class InvocationServer {
public void invoke() {
if (method != null) {
if (method.checkParameters(request)) {
- method.invoke(request);
+ if (method.requestAccessFilter().allow(request)) {
+ method.invoke(request);
+ } else {
+ request.setError(ErrorCode.PERMISSION_DENIED, "Permission denied");
+ }
} else {
request.setError(ErrorCode.WRONG_PARAMS, "Parameters in " + request + " does not match " + method);
}
diff --git a/jrt/src/com/yahoo/jrt/Method.java b/jrt/src/com/yahoo/jrt/Method.java
index 4fc9f0714da..89c66747e0b 100644
--- a/jrt/src/com/yahoo/jrt/Method.java
+++ b/jrt/src/com/yahoo/jrt/Method.java
@@ -40,6 +40,8 @@ public class Method {
private String[] returnName;
private String[] returnDesc;
+ private RequestAccessFilter filter = RequestAccessFilter.ALLOW_ALL;
+
private static final String undocumented = "???";
@@ -147,6 +149,10 @@ public class Method {
return this;
}
+ public Method requestAccessFilter(RequestAccessFilter filter) { this.filter = filter; return this; }
+
+ public RequestAccessFilter requestAccessFilter() { return filter; }
+
/**
* Obtain the name of a parameter
*
diff --git a/jrt/src/com/yahoo/jrt/RequestAccessFilter.java b/jrt/src/com/yahoo/jrt/RequestAccessFilter.java
new file mode 100644
index 00000000000..6701436d6ce
--- /dev/null
+++ b/jrt/src/com/yahoo/jrt/RequestAccessFilter.java
@@ -0,0 +1,17 @@
+// Copyright Yahoo. Licensed under the terms of the Apache 2.0 license. See LICENSE in the project root.
+package com.yahoo.jrt;
+
+/**
+ * Request access filter is invoked before any call to {@link Method#invoke(Request)}.
+ * If {@link #allow(Request)} returns false, the method is not invoked, and the request is failed with error
+ * {@link ErrorCode#PERMISSION_DENIED}.
+ *
+ * @author bjorncs
+ */
+public interface RequestAccessFilter {
+
+ RequestAccessFilter ALLOW_ALL = __ -> true;
+
+ boolean allow(Request r);
+
+}
diff --git a/jrt/tests/com/yahoo/jrt/InvokeErrorTest.java b/jrt/tests/com/yahoo/jrt/InvokeErrorTest.java
index a9a0b18b5a1..4fa06eec56f 100644
--- a/jrt/tests/com/yahoo/jrt/InvokeErrorTest.java
+++ b/jrt/tests/com/yahoo/jrt/InvokeErrorTest.java
@@ -6,6 +6,7 @@ import org.junit.After;
import org.junit.Before;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
public class InvokeErrorTest {
@@ -16,6 +17,7 @@ public class InvokeErrorTest {
Supervisor client;
Target target;
Test.Barrier barrier;
+ SimpleRequestAccessFilter filter;
@Before
public void setUp() throws ListenFailedException {
@@ -23,7 +25,8 @@ public class InvokeErrorTest {
client = new Supervisor(new Transport());
acceptor = server.listen(new Spec(0));
target = client.connect(new Spec("localhost", acceptor.port()));
- server.addMethod(new Method("test", "iib", "i", this::rpc_test));
+ filter = new SimpleRequestAccessFilter();
+ server.addMethod(new Method("test", "iib", "i", this::rpc_test).requestAccessFilter(filter));
server.addMethod(new Method("test_barrier", "iib", "i", this::rpc_test_barrier));
barrier = new Test.Barrier();
}
@@ -157,4 +160,36 @@ public class InvokeErrorTest {
assertEquals(ErrorCode.CONNECTION, req1.errorCode());
}
+ @org.junit.Test
+ public void testFilterIsInvoked() {
+ Request r = new Request("test");
+ r.parameters().add(new Int32Value(42));
+ r.parameters().add(new Int32Value(0));
+ r.parameters().add(new Int8Value((byte)0));
+ assertFalse(filter.invoked);
+ target.invokeSync(r, timeout);
+ assertFalse(r.isError());
+ assertTrue(filter.invoked);
+ }
+
+ @org.junit.Test
+ public void testFilterFailsRequest() {
+ Request r = new Request("test");
+ r.parameters().add(new Int32Value(42));
+ r.parameters().add(new Int32Value(0));
+ r.parameters().add(new Int8Value((byte)0));
+ filter.allowed = false;
+ assertFalse(filter.invoked);
+ target.invokeSync(r, timeout);
+ assertTrue(r.isError());
+ assertTrue(filter.invoked);
+ assertEquals(ErrorCode.PERMISSION_DENIED, r.errorCode());
+ assertEquals("Permission denied", r.errorMessage());
+ }
+
+ private static class SimpleRequestAccessFilter implements RequestAccessFilter {
+ boolean invoked = false, allowed = true;
+ @Override public boolean allow(Request r) { invoked = true; return allowed; }
+ }
+
}