Move remaining check methods in RestEntitlementsCheckAction (#125351)

All future check methods should be found reflectively with the
EntitlementTest annotation.
This commit is contained in:
Ryan Ernst 2025-03-21 12:00:39 -07:00 committed by GitHub
parent d7995975d9
commit 02f12c8e83
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 213 additions and 272 deletions

View file

@ -9,7 +9,12 @@
package org.elasticsearch.entitlement.qa.test; package org.elasticsearch.entitlement.qa.test;
import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS;
@SuppressWarnings({ "unused" /* called via reflection */ })
class LoadNativeLibrariesCheckActions { class LoadNativeLibrariesCheckActions {
@EntitlementTest(expectedAccess = PLUGINS)
static void runtimeLoad() { static void runtimeLoad() {
try { try {
Runtime.getRuntime().load(FileCheckActions.readDir().resolve("libSomeLibFile.so").toString()); Runtime.getRuntime().load(FileCheckActions.readDir().resolve("libSomeLibFile.so").toString());
@ -18,6 +23,7 @@ class LoadNativeLibrariesCheckActions {
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void systemLoad() { static void systemLoad() {
try { try {
System.load(FileCheckActions.readDir().resolve("libSomeLibFile.so").toString()); System.load(FileCheckActions.readDir().resolve("libSomeLibFile.so").toString());
@ -26,6 +32,7 @@ class LoadNativeLibrariesCheckActions {
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void runtimeLoadLibrary() { static void runtimeLoadLibrary() {
try { try {
Runtime.getRuntime().loadLibrary("SomeLib"); Runtime.getRuntime().loadLibrary("SomeLib");
@ -34,6 +41,7 @@ class LoadNativeLibrariesCheckActions {
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void systemLoadLibrary() { static void systemLoadLibrary() {
try { try {
System.loadLibrary("SomeLib"); System.loadLibrary("SomeLib");
@ -41,4 +49,6 @@ class LoadNativeLibrariesCheckActions {
// The library does not exist, so we expect to fail loading it // The library does not exist, so we expect to fail loading it
} }
} }
private LoadNativeLibrariesCheckActions() {}
} }

View file

@ -12,12 +12,23 @@ package org.elasticsearch.entitlement.qa.test;
import org.elasticsearch.core.SuppressForbidden; import org.elasticsearch.core.SuppressForbidden;
import java.io.IOException; import java.io.IOException;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.HttpURLConnection;
import java.net.InetAddress; import java.net.InetAddress;
import java.net.InetSocketAddress; import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.NetworkInterface;
import java.net.Proxy; import java.net.Proxy;
import java.net.ProxySelector;
import java.net.ResponseCache;
import java.net.ServerSocket; import java.net.ServerSocket;
import java.net.Socket; import java.net.Socket;
import java.net.SocketException; import java.net.SocketException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.spi.URLStreamHandlerProvider;
import java.nio.ByteBuffer; import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel; import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel; import java.nio.channels.AsynchronousSocketChannel;
@ -32,9 +43,17 @@ import java.security.cert.CertStore;
import java.util.Arrays; import java.util.Arrays;
import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutionException;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.ALWAYS_DENIED;
import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS;
@SuppressForbidden(reason = "Testing entitlement check on forbidden action") @SuppressForbidden(reason = "Testing entitlement check on forbidden action")
@SuppressWarnings({ "unused" /* called via reflection */, "deprecation" })
class NetworkAccessCheckActions { class NetworkAccessCheckActions {
@EntitlementTest(expectedAccess = PLUGINS)
static void serverSocketAccept() throws IOException { static void serverSocketAccept() throws IOException {
try (ServerSocket socket = new DummyImplementations.DummyBoundServerSocket()) { try (ServerSocket socket = new DummyImplementations.DummyBoundServerSocket()) {
try { try {
@ -49,30 +68,35 @@ class NetworkAccessCheckActions {
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void serverSocketBind() throws IOException { static void serverSocketBind() throws IOException {
try (ServerSocket socket = new DummyImplementations.DummyServerSocket()) { try (ServerSocket socket = new DummyImplementations.DummyServerSocket()) {
socket.bind(null); socket.bind(null);
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void createSocketWithProxy() throws IOException { static void createSocketWithProxy() throws IOException {
try (Socket socket = new Socket(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(0)))) { try (Socket socket = new Socket(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(0)))) {
assert socket.isBound() == false; assert socket.isBound() == false;
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void socketBind() throws IOException { static void socketBind() throws IOException {
try (Socket socket = new DummyImplementations.DummySocket()) { try (Socket socket = new DummyImplementations.DummySocket()) {
socket.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); socket.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void socketConnect() throws IOException { static void socketConnect() throws IOException {
try (Socket socket = new DummyImplementations.DummySocket()) { try (Socket socket = new DummyImplementations.DummySocket()) {
socket.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); socket.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void createLDAPCertStore() { static void createLDAPCertStore() {
try { try {
// We pass down null params to provoke a InvalidAlgorithmParameterException // We pass down null params to provoke a InvalidAlgorithmParameterException
@ -86,18 +110,21 @@ class NetworkAccessCheckActions {
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void serverSocketChannelBind() throws IOException { static void serverSocketChannelBind() throws IOException {
try (var serverSocketChannel = ServerSocketChannel.open()) { try (var serverSocketChannel = ServerSocketChannel.open()) {
serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void serverSocketChannelBindWithBacklog() throws IOException { static void serverSocketChannelBindWithBacklog() throws IOException {
try (var serverSocketChannel = ServerSocketChannel.open()) { try (var serverSocketChannel = ServerSocketChannel.open()) {
serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 50); serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 50);
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void serverSocketChannelAccept() throws IOException { static void serverSocketChannelAccept() throws IOException {
try (var serverSocketChannel = ServerSocketChannel.open()) { try (var serverSocketChannel = ServerSocketChannel.open()) {
serverSocketChannel.configureBlocking(false); serverSocketChannel.configureBlocking(false);
@ -110,18 +137,21 @@ class NetworkAccessCheckActions {
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void asynchronousServerSocketChannelBind() throws IOException { static void asynchronousServerSocketChannelBind() throws IOException {
try (var serverSocketChannel = AsynchronousServerSocketChannel.open()) { try (var serverSocketChannel = AsynchronousServerSocketChannel.open()) {
serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void asynchronousServerSocketChannelBindWithBacklog() throws IOException { static void asynchronousServerSocketChannelBindWithBacklog() throws IOException {
try (var serverSocketChannel = AsynchronousServerSocketChannel.open()) { try (var serverSocketChannel = AsynchronousServerSocketChannel.open()) {
serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 50); serverSocketChannel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), 50);
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void asynchronousServerSocketChannelAccept() throws IOException { static void asynchronousServerSocketChannelAccept() throws IOException {
try (var serverSocketChannel = AsynchronousServerSocketChannel.open()) { try (var serverSocketChannel = AsynchronousServerSocketChannel.open()) {
try { try {
@ -134,6 +164,7 @@ class NetworkAccessCheckActions {
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void asynchronousServerSocketChannelAcceptWithHandler() throws IOException { static void asynchronousServerSocketChannelAcceptWithHandler() throws IOException {
try (var serverSocketChannel = AsynchronousServerSocketChannel.open()) { try (var serverSocketChannel = AsynchronousServerSocketChannel.open()) {
try { try {
@ -153,12 +184,14 @@ class NetworkAccessCheckActions {
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void socketChannelBind() throws IOException { static void socketChannelBind() throws IOException {
try (var socketChannel = SocketChannel.open()) { try (var socketChannel = SocketChannel.open()) {
socketChannel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); socketChannel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void socketChannelConnect() throws IOException { static void socketChannelConnect() throws IOException {
try (var socketChannel = SocketChannel.open()) { try (var socketChannel = SocketChannel.open()) {
try { try {
@ -170,12 +203,14 @@ class NetworkAccessCheckActions {
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void asynchronousSocketChannelBind() throws IOException { static void asynchronousSocketChannelBind() throws IOException {
try (var socketChannel = AsynchronousSocketChannel.open()) { try (var socketChannel = AsynchronousSocketChannel.open()) {
socketChannel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); socketChannel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void asynchronousSocketChannelConnect() throws IOException, InterruptedException { static void asynchronousSocketChannelConnect() throws IOException, InterruptedException {
try (var socketChannel = AsynchronousSocketChannel.open()) { try (var socketChannel = AsynchronousSocketChannel.open()) {
var future = socketChannel.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); var future = socketChannel.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
@ -189,6 +224,7 @@ class NetworkAccessCheckActions {
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void asynchronousSocketChannelConnectWithCompletion() throws IOException { static void asynchronousSocketChannelConnectWithCompletion() throws IOException {
try (var socketChannel = AsynchronousSocketChannel.open()) { try (var socketChannel = AsynchronousSocketChannel.open()) {
socketChannel.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), null, new CompletionHandler<>() { socketChannel.connect(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0), null, new CompletionHandler<>() {
@ -203,12 +239,14 @@ class NetworkAccessCheckActions {
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void datagramChannelBind() throws IOException { static void datagramChannelBind() throws IOException {
try (var channel = DatagramChannel.open()) { try (var channel = DatagramChannel.open()) {
channel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0)); channel.bind(new InetSocketAddress(InetAddress.getLoopbackAddress(), 0));
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void datagramChannelConnect() throws IOException { static void datagramChannelConnect() throws IOException {
try (var channel = DatagramChannel.open()) { try (var channel = DatagramChannel.open()) {
channel.configureBlocking(false); channel.configureBlocking(false);
@ -221,6 +259,7 @@ class NetworkAccessCheckActions {
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void datagramChannelSend() throws IOException { static void datagramChannelSend() throws IOException {
try (var channel = DatagramChannel.open()) { try (var channel = DatagramChannel.open()) {
channel.configureBlocking(false); channel.configureBlocking(false);
@ -228,6 +267,7 @@ class NetworkAccessCheckActions {
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void datagramChannelReceive() throws IOException { static void datagramChannelReceive() throws IOException {
try (var channel = DatagramChannel.open()) { try (var channel = DatagramChannel.open()) {
channel.configureBlocking(false); channel.configureBlocking(false);
@ -235,4 +275,149 @@ class NetworkAccessCheckActions {
channel.receive(ByteBuffer.wrap(buffer)); channel.receive(ByteBuffer.wrap(buffer));
} }
} }
@EntitlementTest(expectedAccess = ALWAYS_DENIED)
static void createURLStreamHandlerProvider() {
var x = new URLStreamHandlerProvider() {
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
return null;
}
};
}
@EntitlementTest(expectedAccess = ALWAYS_DENIED)
static void createURLWithURLStreamHandler() throws MalformedURLException {
var x = new URL("http", "host", 1234, "file", new URLStreamHandler() {
@Override
protected URLConnection openConnection(URL u) {
return null;
}
});
}
@EntitlementTest(expectedAccess = ALWAYS_DENIED)
static void createURLWithURLStreamHandler2() throws MalformedURLException {
var x = new URL(null, "spec", new URLStreamHandler() {
@Override
protected URLConnection openConnection(URL u) {
return null;
}
});
}
@EntitlementTest(expectedAccess = ALWAYS_DENIED)
static void setDefaultResponseCache() {
ResponseCache.setDefault(null);
}
@EntitlementTest(expectedAccess = ALWAYS_DENIED)
static void setDefaultProxySelector() {
ProxySelector.setDefault(null);
}
@EntitlementTest(expectedAccess = ALWAYS_DENIED)
static void setDefaultSSLContext() throws NoSuchAlgorithmException {
SSLContext.setDefault(SSLContext.getDefault());
}
@EntitlementTest(expectedAccess = ALWAYS_DENIED)
static void setDefaultHostnameVerifier() {
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> false);
}
@EntitlementTest(expectedAccess = ALWAYS_DENIED)
static void setDefaultSSLSocketFactory() {
HttpsURLConnection.setDefaultSSLSocketFactory(new DummyImplementations.DummySSLSocketFactory());
}
@EntitlementTest(expectedAccess = PLUGINS)
static void setHttpsConnectionProperties() {
new DummyImplementations.DummyHttpsURLConnection().setSSLSocketFactory(new DummyImplementations.DummySSLSocketFactory());
}
@EntitlementTest(expectedAccess = ALWAYS_DENIED)
static void datagramSocket$$setDatagramSocketImplFactory() throws IOException {
DatagramSocket.setDatagramSocketImplFactory(() -> { throw new IllegalStateException(); });
}
@EntitlementTest(expectedAccess = ALWAYS_DENIED)
static void httpURLConnection$$setFollowRedirects() {
HttpURLConnection.setFollowRedirects(HttpURLConnection.getFollowRedirects());
}
@EntitlementTest(expectedAccess = ALWAYS_DENIED)
static void serverSocket$$setSocketFactory() throws IOException {
ServerSocket.setSocketFactory(() -> { throw new IllegalStateException(); });
}
@EntitlementTest(expectedAccess = ALWAYS_DENIED)
static void socket$$setSocketImplFactory() throws IOException {
Socket.setSocketImplFactory(() -> { throw new IllegalStateException(); });
}
@EntitlementTest(expectedAccess = ALWAYS_DENIED)
static void url$$setURLStreamHandlerFactory() {
URL.setURLStreamHandlerFactory(__ -> { throw new IllegalStateException(); });
}
@EntitlementTest(expectedAccess = ALWAYS_DENIED)
static void urlConnection$$setFileNameMap() {
URLConnection.setFileNameMap(__ -> { throw new IllegalStateException(); });
}
@EntitlementTest(expectedAccess = ALWAYS_DENIED)
static void urlConnection$$setContentHandlerFactory() {
URLConnection.setContentHandlerFactory(__ -> { throw new IllegalStateException(); });
}
@EntitlementTest(expectedAccess = PLUGINS)
static void bindDatagramSocket() throws SocketException {
try (var socket = new DatagramSocket(null)) {
socket.bind(null);
}
}
@EntitlementTest(expectedAccess = PLUGINS)
static void connectDatagramSocket() throws SocketException {
try (var socket = new DummyImplementations.DummyDatagramSocket()) {
socket.connect(new InetSocketAddress(1234));
}
}
@EntitlementTest(expectedAccess = PLUGINS)
static void joinGroupDatagramSocket() throws IOException {
try (var socket = new DummyImplementations.DummyDatagramSocket()) {
socket.joinGroup(
new InetSocketAddress(InetAddress.getByAddress(new byte[] { (byte) 230, 0, 0, 1 }), 1234),
NetworkInterface.getByIndex(0)
);
}
}
@EntitlementTest(expectedAccess = PLUGINS)
static void leaveGroupDatagramSocket() throws IOException {
try (var socket = new DummyImplementations.DummyDatagramSocket()) {
socket.leaveGroup(
new InetSocketAddress(InetAddress.getByAddress(new byte[] { (byte) 230, 0, 0, 1 }), 1234),
NetworkInterface.getByIndex(0)
);
}
}
@EntitlementTest(expectedAccess = PLUGINS)
static void sendDatagramSocket() throws IOException {
try (var socket = new DummyImplementations.DummyDatagramSocket()) {
socket.send(new DatagramPacket(new byte[] { 0 }, 1, InetAddress.getLocalHost(), 1234));
}
}
@EntitlementTest(expectedAccess = PLUGINS)
static void receiveDatagramSocket() throws IOException {
try (var socket = new DummyImplementations.DummyDatagramSocket()) {
socket.receive(new DatagramPacket(new byte[1], 1, InetAddress.getLocalHost(), 1234));
}
}
private NetworkAccessCheckActions() {}
} }

View file

@ -12,9 +12,7 @@ package org.elasticsearch.entitlement.qa.test;
import org.elasticsearch.client.internal.node.NodeClient; import org.elasticsearch.client.internal.node.NodeClient;
import org.elasticsearch.common.Strings; import org.elasticsearch.common.Strings;
import org.elasticsearch.core.CheckedConsumer; import org.elasticsearch.core.CheckedConsumer;
import org.elasticsearch.core.CheckedRunnable;
import org.elasticsearch.core.SuppressForbidden; import org.elasticsearch.core.SuppressForbidden;
import org.elasticsearch.entitlement.runtime.api.NotEntitledException;
import org.elasticsearch.env.Environment; import org.elasticsearch.env.Environment;
import org.elasticsearch.logging.LogManager; import org.elasticsearch.logging.LogManager;
import org.elasticsearch.logging.Logger; import org.elasticsearch.logging.Logger;
@ -23,27 +21,9 @@ import org.elasticsearch.rest.RestRequest;
import org.elasticsearch.rest.RestResponse; import org.elasticsearch.rest.RestResponse;
import org.elasticsearch.rest.RestStatus; import org.elasticsearch.rest.RestStatus;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException; import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method; import java.lang.reflect.Method;
import java.lang.reflect.Modifier; import java.lang.reflect.Modifier;
import java.net.DatagramPacket;
import java.net.DatagramSocket;
import java.net.HttpURLConnection;
import java.net.InetAddress;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.NetworkInterface;
import java.net.ProxySelector;
import java.net.ResponseCache;
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.spi.URLStreamHandlerProvider;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -53,16 +33,9 @@ import java.util.function.Function;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import java.util.stream.Stream; import java.util.stream.Stream;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import static java.util.Map.entry; import static java.util.Map.entry;
import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.ALWAYS_ALLOWED; import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.ALWAYS_ALLOWED;
import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.ALWAYS_DENIED;
import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS; import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS;
import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.SERVER_ONLY;
import static org.elasticsearch.entitlement.qa.test.RestEntitlementsCheckAction.CheckAction.alwaysDenied;
import static org.elasticsearch.entitlement.qa.test.RestEntitlementsCheckAction.CheckAction.forPlugins;
import static org.elasticsearch.rest.RestRequest.Method.GET; import static org.elasticsearch.rest.RestRequest.Method.GET;
@SuppressWarnings("unused") @SuppressWarnings("unused")
@ -74,128 +47,25 @@ public class RestEntitlementsCheckAction extends BaseRestHandler {
EntitlementTest.ExpectedAccess expectedAccess, EntitlementTest.ExpectedAccess expectedAccess,
Class<? extends Exception> expectedExceptionIfDenied, Class<? extends Exception> expectedExceptionIfDenied,
Integer fromJavaVersion Integer fromJavaVersion
) { ) {}
/**
* These cannot be granted to plugins, so our test plugins cannot test the "allowed" case.
*/
static CheckAction deniedToPlugins(CheckedRunnable<Exception> action) {
return new CheckAction(env -> action.run(), SERVER_ONLY, NotEntitledException.class, null);
}
static CheckAction forPlugins(CheckedRunnable<Exception> action) {
return new CheckAction(env -> action.run(), PLUGINS, NotEntitledException.class, null);
}
static CheckAction alwaysDenied(CheckedRunnable<Exception> action) {
return new CheckAction(env -> action.run(), ALWAYS_DENIED, NotEntitledException.class, null);
}
}
private static final Map<String, CheckAction> checkActions = Stream.of( private static final Map<String, CheckAction> checkActions = Stream.of(
Stream.<Entry<String, CheckAction>>of(
entry("set_https_connection_properties", forPlugins(RestEntitlementsCheckAction::setHttpsConnectionProperties)),
entry("set_default_ssl_socket_factory", alwaysDenied(RestEntitlementsCheckAction::setDefaultSSLSocketFactory)),
entry("set_default_hostname_verifier", alwaysDenied(RestEntitlementsCheckAction::setDefaultHostnameVerifier)),
entry("set_default_ssl_context", alwaysDenied(RestEntitlementsCheckAction::setDefaultSSLContext)),
// This group is a bit nasty: if entitlements don't prevent these, then networking is
// irreparably borked for the remainder of the test run.
entry(
"datagramSocket_setDatagramSocketImplFactory",
alwaysDenied(RestEntitlementsCheckAction::datagramSocket$$setDatagramSocketImplFactory)
),
entry("httpURLConnection_setFollowRedirects", alwaysDenied(RestEntitlementsCheckAction::httpURLConnection$$setFollowRedirects)),
entry("serverSocket_setSocketFactory", alwaysDenied(RestEntitlementsCheckAction::serverSocket$$setSocketFactory)),
entry("socket_setSocketImplFactory", alwaysDenied(RestEntitlementsCheckAction::socket$$setSocketImplFactory)),
entry("url_setURLStreamHandlerFactory", alwaysDenied(RestEntitlementsCheckAction::url$$setURLStreamHandlerFactory)),
entry("urlConnection_setFileNameMap", alwaysDenied(RestEntitlementsCheckAction::urlConnection$$setFileNameMap)),
entry(
"urlConnection_setContentHandlerFactory",
alwaysDenied(RestEntitlementsCheckAction::urlConnection$$setContentHandlerFactory)
),
entry("proxySelector_setDefault", alwaysDenied(RestEntitlementsCheckAction::setDefaultProxySelector)),
entry("responseCache_setDefault", alwaysDenied(RestEntitlementsCheckAction::setDefaultResponseCache)),
entry(
"createInetAddressResolverProvider",
new CheckAction(
env -> VersionSpecificNetworkChecks.createInetAddressResolverProvider(),
SERVER_ONLY,
NotEntitledException.class,
18
)
),
entry("createURLStreamHandlerProvider", alwaysDenied(RestEntitlementsCheckAction::createURLStreamHandlerProvider)),
entry("createURLWithURLStreamHandler", alwaysDenied(RestEntitlementsCheckAction::createURLWithURLStreamHandler)),
entry("createURLWithURLStreamHandler2", alwaysDenied(RestEntitlementsCheckAction::createURLWithURLStreamHandler2)),
entry("datagram_socket_bind", forPlugins(RestEntitlementsCheckAction::bindDatagramSocket)),
entry("datagram_socket_connect", forPlugins(RestEntitlementsCheckAction::connectDatagramSocket)),
entry("datagram_socket_send", forPlugins(RestEntitlementsCheckAction::sendDatagramSocket)),
entry("datagram_socket_receive", forPlugins(RestEntitlementsCheckAction::receiveDatagramSocket)),
entry("datagram_socket_join_group", forPlugins(RestEntitlementsCheckAction::joinGroupDatagramSocket)),
entry("datagram_socket_leave_group", forPlugins(RestEntitlementsCheckAction::leaveGroupDatagramSocket)),
entry("create_socket_with_proxy", forPlugins(NetworkAccessCheckActions::createSocketWithProxy)),
entry("socket_bind", forPlugins(NetworkAccessCheckActions::socketBind)),
entry("socket_connect", forPlugins(NetworkAccessCheckActions::socketConnect)),
entry("server_socket_bind", forPlugins(NetworkAccessCheckActions::serverSocketBind)),
entry("server_socket_accept", forPlugins(NetworkAccessCheckActions::serverSocketAccept)),
entry("http_client_send", forPlugins(VersionSpecificNetworkChecks::httpClientSend)),
entry("http_client_send_async", forPlugins(VersionSpecificNetworkChecks::httpClientSendAsync)),
entry("create_ldap_cert_store", forPlugins(NetworkAccessCheckActions::createLDAPCertStore)),
entry("server_socket_channel_bind", forPlugins(NetworkAccessCheckActions::serverSocketChannelBind)),
entry("server_socket_channel_bind_backlog", forPlugins(NetworkAccessCheckActions::serverSocketChannelBindWithBacklog)),
entry("server_socket_channel_accept", forPlugins(NetworkAccessCheckActions::serverSocketChannelAccept)),
entry("asynchronous_server_socket_channel_bind", forPlugins(NetworkAccessCheckActions::asynchronousServerSocketChannelBind)),
entry(
"asynchronous_server_socket_channel_bind_backlog",
forPlugins(NetworkAccessCheckActions::asynchronousServerSocketChannelBindWithBacklog)
),
entry(
"asynchronous_server_socket_channel_accept",
forPlugins(NetworkAccessCheckActions::asynchronousServerSocketChannelAccept)
),
entry(
"asynchronous_server_socket_channel_accept_with_handler",
forPlugins(NetworkAccessCheckActions::asynchronousServerSocketChannelAcceptWithHandler)
),
entry("socket_channel_bind", forPlugins(NetworkAccessCheckActions::socketChannelBind)),
entry("socket_channel_connect", forPlugins(NetworkAccessCheckActions::socketChannelConnect)),
entry("asynchronous_socket_channel_bind", forPlugins(NetworkAccessCheckActions::asynchronousSocketChannelBind)),
entry("asynchronous_socket_channel_connect", forPlugins(NetworkAccessCheckActions::asynchronousSocketChannelConnect)),
entry(
"asynchronous_socket_channel_connect_with_completion",
forPlugins(NetworkAccessCheckActions::asynchronousSocketChannelConnectWithCompletion)
),
entry("datagram_channel_bind", forPlugins(NetworkAccessCheckActions::datagramChannelBind)),
entry("datagram_channel_connect", forPlugins(NetworkAccessCheckActions::datagramChannelConnect)),
entry("datagram_channel_send", forPlugins(NetworkAccessCheckActions::datagramChannelSend)),
entry("datagram_channel_receive", forPlugins(NetworkAccessCheckActions::datagramChannelReceive)),
entry("runtime_load", forPlugins(LoadNativeLibrariesCheckActions::runtimeLoad)),
entry("runtime_load_library", forPlugins(LoadNativeLibrariesCheckActions::runtimeLoadLibrary)),
entry("system_load", forPlugins(LoadNativeLibrariesCheckActions::systemLoad)),
entry("system_load_library", forPlugins(LoadNativeLibrariesCheckActions::systemLoadLibrary))
// MAINTENANCE NOTE: Please don't add any more entries to this map.
// Put new tests into their own "Actions" class using the @EntitlementTest annotation.
),
getTestEntries(FileCheckActions.class), getTestEntries(FileCheckActions.class),
getTestEntries(FileStoreActions.class), getTestEntries(FileStoreActions.class),
getTestEntries(JvmActions.class),
getTestEntries(LoadNativeLibrariesCheckActions.class),
getTestEntries(ManageThreadsActions.class), getTestEntries(ManageThreadsActions.class),
getTestEntries(NativeActions.class), getTestEntries(NativeActions.class),
getTestEntries(NetworkAccessCheckActions.class),
getTestEntries(NioChannelsActions.class), getTestEntries(NioChannelsActions.class),
getTestEntries(NioFilesActions.class), getTestEntries(NioFilesActions.class),
getTestEntries(NioFileSystemActions.class), getTestEntries(NioFileSystemActions.class),
getTestEntries(OperatingSystemActions.class),
getTestEntries(PathActions.class), getTestEntries(PathActions.class),
getTestEntries(SpiActions.class), getTestEntries(SpiActions.class),
getTestEntries(SystemActions.class), getTestEntries(SystemActions.class),
getTestEntries(URLConnectionFileActions.class), getTestEntries(URLConnectionFileActions.class),
getTestEntries(URLConnectionNetworkActions.class), getTestEntries(URLConnectionNetworkActions.class)
getTestEntries(JvmActions.class),
getTestEntries(OperatingSystemActions.class)
) )
.flatMap(Function.identity()) .flatMap(Function.identity())
.filter(entry -> entry.getValue().fromJavaVersion() == null || Runtime.version().feature() >= entry.getValue().fromJavaVersion()) .filter(entry -> entry.getValue().fromJavaVersion() == null || Runtime.version().feature() >= entry.getValue().fromJavaVersion())
@ -258,143 +128,11 @@ public class RestEntitlementsCheckAction extends BaseRestHandler {
throw new AssertionError("Entitlement test method [" + method + "] must have no parameters or 1 parameter (Environment)"); throw new AssertionError("Entitlement test method [" + method + "] must have no parameters or 1 parameter (Environment)");
} }
private static void createURLStreamHandlerProvider() {
var x = new URLStreamHandlerProvider() {
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
return null;
}
};
}
@SuppressWarnings("deprecation")
private static void createURLWithURLStreamHandler() throws MalformedURLException {
var x = new URL("http", "host", 1234, "file", new URLStreamHandler() {
@Override
protected URLConnection openConnection(URL u) {
return null;
}
});
}
@SuppressWarnings("deprecation")
private static void createURLWithURLStreamHandler2() throws MalformedURLException {
var x = new URL(null, "spec", new URLStreamHandler() {
@Override
protected URLConnection openConnection(URL u) {
return null;
}
});
}
private static void setDefaultResponseCache() {
ResponseCache.setDefault(null);
}
private static void setDefaultProxySelector() {
ProxySelector.setDefault(null);
}
private static void setDefaultSSLContext() throws NoSuchAlgorithmException {
SSLContext.setDefault(SSLContext.getDefault());
}
private static void setDefaultHostnameVerifier() {
HttpsURLConnection.setDefaultHostnameVerifier((hostname, session) -> false);
}
private static void setDefaultSSLSocketFactory() {
HttpsURLConnection.setDefaultSSLSocketFactory(new DummyImplementations.DummySSLSocketFactory());
}
private static void setHttpsConnectionProperties() {
new DummyImplementations.DummyHttpsURLConnection().setSSLSocketFactory(new DummyImplementations.DummySSLSocketFactory());
}
@SuppressWarnings("deprecation")
@SuppressForbidden(reason = "We're required to prevent calls to this forbidden API")
private static void datagramSocket$$setDatagramSocketImplFactory() throws IOException {
DatagramSocket.setDatagramSocketImplFactory(() -> { throw new IllegalStateException(); });
}
private static void httpURLConnection$$setFollowRedirects() {
HttpURLConnection.setFollowRedirects(HttpURLConnection.getFollowRedirects());
}
@SuppressWarnings("deprecation")
@SuppressForbidden(reason = "We're required to prevent calls to this forbidden API")
private static void serverSocket$$setSocketFactory() throws IOException {
ServerSocket.setSocketFactory(() -> { throw new IllegalStateException(); });
}
@SuppressWarnings("deprecation")
@SuppressForbidden(reason = "We're required to prevent calls to this forbidden API")
private static void socket$$setSocketImplFactory() throws IOException {
Socket.setSocketImplFactory(() -> { throw new IllegalStateException(); });
}
private static void url$$setURLStreamHandlerFactory() {
URL.setURLStreamHandlerFactory(__ -> { throw new IllegalStateException(); });
}
private static void urlConnection$$setFileNameMap() {
URLConnection.setFileNameMap(__ -> { throw new IllegalStateException(); });
}
private static void urlConnection$$setContentHandlerFactory() {
URLConnection.setContentHandlerFactory(__ -> { throw new IllegalStateException(); });
}
private static void bindDatagramSocket() throws SocketException {
try (var socket = new DatagramSocket(null)) {
socket.bind(null);
}
}
@SuppressForbidden(reason = "testing entitlements")
private static void connectDatagramSocket() throws SocketException {
try (var socket = new DummyImplementations.DummyDatagramSocket()) {
socket.connect(new InetSocketAddress(1234));
}
}
private static void joinGroupDatagramSocket() throws IOException {
try (var socket = new DummyImplementations.DummyDatagramSocket()) {
socket.joinGroup(
new InetSocketAddress(InetAddress.getByAddress(new byte[] { (byte) 230, 0, 0, 1 }), 1234),
NetworkInterface.getByIndex(0)
);
}
}
private static void leaveGroupDatagramSocket() throws IOException {
try (var socket = new DummyImplementations.DummyDatagramSocket()) {
socket.leaveGroup(
new InetSocketAddress(InetAddress.getByAddress(new byte[] { (byte) 230, 0, 0, 1 }), 1234),
NetworkInterface.getByIndex(0)
);
}
}
@SuppressForbidden(reason = "testing entitlements")
private static void sendDatagramSocket() throws IOException {
try (var socket = new DummyImplementations.DummyDatagramSocket()) {
socket.send(new DatagramPacket(new byte[] { 0 }, 1, InetAddress.getLocalHost(), 1234));
}
}
@SuppressForbidden(reason = "testing entitlements")
private static void receiveDatagramSocket() throws IOException {
try (var socket = new DummyImplementations.DummyDatagramSocket()) {
socket.receive(new DatagramPacket(new byte[1], 1, InetAddress.getLocalHost(), 1234));
}
}
public static Set<String> getCheckActionsAllowedInPlugins() { public static Set<String> getCheckActionsAllowedInPlugins() {
return checkActions.entrySet() return checkActions.entrySet()
.stream() .stream()
.filter(kv -> kv.getValue().expectedAccess().equals(PLUGINS) || kv.getValue().expectedAccess().equals(ALWAYS_ALLOWED)) .filter(kv -> kv.getValue().expectedAccess().equals(PLUGINS) || kv.getValue().expectedAccess().equals(ALWAYS_ALLOWED))
.map(Entry::getKey) .map(Map.Entry::getKey)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }
@ -402,7 +140,7 @@ public class RestEntitlementsCheckAction extends BaseRestHandler {
return checkActions.entrySet() return checkActions.entrySet()
.stream() .stream()
.filter(kv -> kv.getValue().expectedAccess().equals(ALWAYS_ALLOWED)) .filter(kv -> kv.getValue().expectedAccess().equals(ALWAYS_ALLOWED))
.map(Entry::getKey) .map(Map.Entry::getKey)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }
@ -410,7 +148,7 @@ public class RestEntitlementsCheckAction extends BaseRestHandler {
return checkActions.entrySet() return checkActions.entrySet()
.stream() .stream()
.filter(kv -> kv.getValue().expectedAccess().equals(ALWAYS_ALLOWED) == false) .filter(kv -> kv.getValue().expectedAccess().equals(ALWAYS_ALLOWED) == false)
.map(Entry::getKey) .map(Map.Entry::getKey)
.collect(Collectors.toSet()); .collect(Collectors.toSet());
} }

View file

@ -17,7 +17,13 @@ import java.net.http.HttpResponse;
import java.net.spi.InetAddressResolver; import java.net.spi.InetAddressResolver;
import java.net.spi.InetAddressResolverProvider; import java.net.spi.InetAddressResolverProvider;
import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS;
import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.SERVER_ONLY;
@SuppressWarnings({ "unused" /* called via reflection */ })
class VersionSpecificNetworkChecks { class VersionSpecificNetworkChecks {
@EntitlementTest(expectedAccess = SERVER_ONLY, fromJavaVersion = 18)
static void createInetAddressResolverProvider() { static void createInetAddressResolverProvider() {
new InetAddressResolverProvider() { new InetAddressResolverProvider() {
@Override @Override
@ -32,6 +38,7 @@ class VersionSpecificNetworkChecks {
}; };
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void httpClientSend() throws InterruptedException { static void httpClientSend() throws InterruptedException {
try (HttpClient httpClient = HttpClient.newBuilder().build()) { try (HttpClient httpClient = HttpClient.newBuilder().build()) {
// Shutdown the client, so the send action will shortcut before actually executing any network operation // Shutdown the client, so the send action will shortcut before actually executing any network operation
@ -45,6 +52,7 @@ class VersionSpecificNetworkChecks {
} }
} }
@EntitlementTest(expectedAccess = PLUGINS)
static void httpClientSendAsync() { static void httpClientSendAsync() {
try (HttpClient httpClient = HttpClient.newBuilder().build()) { try (HttpClient httpClient = HttpClient.newBuilder().build()) {
// Shutdown the client, so the send action will return before actually executing any network operation // Shutdown the client, so the send action will return before actually executing any network operation

View file

@ -52,7 +52,7 @@ public class EntitlementsAllowedViaOverrideIT extends AbstractEntitlementsIT {
@ParametersFactory @ParametersFactory
public static Iterable<Object[]> data() { public static Iterable<Object[]> data() {
return Stream.of("runtime_load_library", "fileList").map(action -> new Object[] { action }).toList(); return Stream.of("runtimeLoadLibrary", "fileList").map(action -> new Object[] { action }).toList();
} }
@Override @Override