diff options
author | Bjørn Christian Seime <bjorncs@yahooinc.com> | 2022-07-19 13:40:00 +0200 |
---|---|---|
committer | Bjørn Christian Seime <bjorncs@yahooinc.com> | 2022-07-20 13:56:33 +0200 |
commit | b10026b7f483c0b1a30b78e4bce8b182f6487b08 (patch) | |
tree | 923bbe8ed6b7ed54145894000ad4137298454bf6 | |
parent | aedcb7eaea2ee9f059ff55f819a6b8f91aaa15ae (diff) |
Introduce per method request access filtering to JRT
-rw-r--r-- | jrt/src/com/yahoo/jrt/ErrorCode.java | 3 | ||||
-rw-r--r-- | jrt/src/com/yahoo/jrt/InvocationServer.java | 6 | ||||
-rw-r--r-- | jrt/src/com/yahoo/jrt/Method.java | 6 | ||||
-rw-r--r-- | jrt/src/com/yahoo/jrt/RequestAccessFilter.java | 17 | ||||
-rw-r--r-- | jrt/tests/com/yahoo/jrt/InvokeErrorTest.java | 37 |
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; } + } + } |