Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -322,9 +322,57 @@ public interface EntitlementChecker {

void check$java_net_Socket$connect(Class<?> callerClass, Socket that, SocketAddress endpoint, int backlog);

// Network miscellanea
// URLConnection (java.net + sun.net.www)

void check$java_net_URL$openConnection(Class<?> callerClass, java.net.URL that);

void check$java_net_URL$openConnection(Class<?> callerClass, java.net.URL that, Proxy proxy);

void check$java_net_URL$openStream(Class<?> callerClass, java.net.URL that);

void check$java_net_URL$getContent(Class<?> callerClass, java.net.URL that);

void check$java_net_URL$getContent(Class<?> callerClass, java.net.URL that, Class<?>[] classes);

void check$java_net_URLConnection$getContentLength(Class<?> callerClass, java.net.URLConnection that);

void check$java_net_URLConnection$getContentLengthLong(Class<?> callerClass, java.net.URLConnection that);

void check$java_net_URLConnection$getContentType(Class<?> callerClass, java.net.URLConnection that);

void check$java_net_URLConnection$getContentEncoding(Class<?> callerClass, java.net.URLConnection that);

void check$java_net_URLConnection$getExpiration(Class<?> callerClass, java.net.URLConnection that);

void check$java_net_URLConnection$getDate(Class<?> callerClass, java.net.URLConnection that);

void check$java_net_URLConnection$getLastModified(Class<?> callerClass, java.net.URLConnection that);

void check$java_net_URLConnection$getHeaderFieldInt(Class<?> callerClass, java.net.URLConnection that, String name, int defaultValue);

void check$java_net_URLConnection$getHeaderFieldLong(Class<?> callerClass, java.net.URLConnection that, String name, long defaultValue);

void check$java_net_URLConnection$getHeaderFieldDate(Class<?> callerClass, java.net.URLConnection that, String name, long defaultValue);

void check$java_net_URLConnection$getContent(Class<?> callerClass, java.net.URLConnection that);

void check$java_net_URLConnection$getContent(Class<?> callerClass, java.net.URLConnection that, Class<?>[] classes);

// Using java.net.URLConnection for "that" as sun.net.www.URLConnection is not exported
void check$sun_net_www_URLConnection$getHeaderField(Class<?> callerClass, java.net.URLConnection that, String name);

void check$sun_net_www_URLConnection$getHeaderFields(Class<?> callerClass, java.net.URLConnection that);

void check$sun_net_www_URLConnection$getHeaderFieldKey(Class<?> callerClass, java.net.URLConnection that, int n);

void check$sun_net_www_URLConnection$getHeaderField(Class<?> callerClass, java.net.URLConnection that, int n);

void check$sun_net_www_URLConnection$getContentType(Class<?> callerClass, java.net.URLConnection that);

void check$sun_net_www_URLConnection$getContentLength(Class<?> callerClass, java.net.URLConnection that);

// Network miscellanea

// HttpClient#send and sendAsync are abstract, so we instrument their internal implementations
void check$jdk_internal_net_http_HttpClientImpl$send(
Class<?> callerClass,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@
import org.elasticsearch.core.SuppressForbidden;

import java.io.IOException;
import java.net.URI;
import java.net.URLConnection;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
Expand Down Expand Up @@ -57,4 +59,8 @@ public static Path createTempDirectoryForWrite() throws IOException {
public static Path createTempSymbolicLink() throws IOException {
return Files.createSymbolicLink(readDir().resolve("entitlements-link-" + random.nextLong()), readWriteDir());
}

public static URLConnection createHttpURLConnection() throws IOException {
return URI.create("http://127.0.0.1:12345/").toURL().openConnection();
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
import java.net.ServerSocket;
import java.net.Socket;
import java.net.SocketException;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
Expand Down Expand Up @@ -75,12 +73,6 @@ static void socketConnect() throws IOException {
}
}

static void urlOpenConnectionWithProxy() throws URISyntaxException, IOException {
var url = new URI("http://localhost").toURL();
var urlConnection = url.openConnection(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(0)));
assert urlConnection != null;
}

static void createLDAPCertStore() {
try {
// We pass down null params to provoke a InvalidAlgorithmParameterException
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,6 @@ static CheckAction alwaysDenied(CheckedRunnable<Exception> action) {
entry("server_socket_bind", forPlugins(NetworkAccessCheckActions::serverSocketBind)),
entry("server_socket_accept", forPlugins(NetworkAccessCheckActions::serverSocketAccept)),

entry("url_open_connection_proxy", forPlugins(NetworkAccessCheckActions::urlOpenConnectionWithProxy)),
entry("http_client_send", forPlugins(VersionSpecificNetworkChecks::httpClientSend)),
entry("http_client_send_async", forPlugins(VersionSpecificNetworkChecks::httpClientSendAsync)),
entry("create_ldap_cert_store", forPlugins(NetworkAccessCheckActions::createLDAPCertStore)),
Expand Down Expand Up @@ -194,7 +193,8 @@ static CheckAction alwaysDenied(CheckedRunnable<Exception> action) {
getTestEntries(NioFileSystemActions.class),
getTestEntries(PathActions.class),
getTestEntries(SpiActions.class),
getTestEntries(SystemActions.class)
getTestEntries(SystemActions.class),
getTestEntries(URLConnectionNetworkActions.class)
)
.flatMap(Function.identity())
.filter(entry -> entry.getValue().fromJavaVersion() == null || Runtime.version().feature() >= entry.getValue().fromJavaVersion())
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,221 @@
/*
* Copyright Elasticsearch B.V. and/or licensed to Elasticsearch B.V. under one
* or more contributor license agreements. Licensed under the "Elastic License
* 2.0", the "GNU Affero General Public License v3.0 only", and the "Server Side
* Public License v 1"; you may not use this file except in compliance with, at
* your election, the "Elastic License 2.0", the "GNU Affero General Public
* License v3.0 only", or the "Server Side Public License, v 1".
*/

package org.elasticsearch.entitlement.qa.test;

import org.elasticsearch.core.CheckedConsumer;
import org.elasticsearch.core.SuppressForbidden;
import org.elasticsearch.entitlement.qa.entitled.EntitledActions;

import java.io.IOException;
import java.io.InputStream;
import java.net.ConnectException;
import java.net.HttpURLConnection;
import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.Proxy;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.net.URLConnection;

import static org.elasticsearch.entitlement.qa.test.EntitlementTest.ExpectedAccess.PLUGINS;

@SuppressWarnings("unused") // everything is called via reflection
class URLConnectionNetworkActions {

private static final URL HTTP_URL;

static {
try {
HTTP_URL = URI.create("http://127.0.0.1/").toURL();
} catch (MalformedURLException e) {
throw new RuntimeException(e);
}
}

private static void withPlainNetworkConnection(CheckedConsumer<URLConnection, Exception> connectionConsumer) throws Exception {
// Create a HttpURLConnection with minimal overrides to test calling directly into URLConnection methods as much as possible
var conn = new HttpURLConnection(HTTP_URL) {
@Override
public void connect() {}

@Override
public void disconnect() {}

@Override
public boolean usingProxy() {
return false;
}

@Override
public InputStream getInputStream() throws IOException {
// Mock an attempt to call connect
throw new ConnectException();
}
};

try {
connectionConsumer.accept(conn);
} catch (java.net.ConnectException e) {
// It's OK, it means we passed entitlement checks, and we tried to connect
}
}

private static void withJdkHttpConnection(CheckedConsumer<HttpURLConnection, Exception> connectionConsumer) throws Exception {
var conn = EntitledActions.createHttpURLConnection();
// Be sure we got the connection implementation we want
assert HttpURLConnection.class.isAssignableFrom(conn.getClass());
try {
connectionConsumer.accept((HttpURLConnection) conn);
} catch (java.net.ConnectException e) {
// It's OK, it means we passed entitlement checks, and we tried to connect
}
}

@EntitlementTest(expectedAccess = PLUGINS)
static void urlOpenConnection() throws Exception {
URI.create("http://127.0.0.1:12345/").toURL().openConnection();
}

@EntitlementTest(expectedAccess = PLUGINS)
@SuppressForbidden(reason = "just testing, not a real connection")
static void urlOpenConnectionWithProxy() throws URISyntaxException, IOException {
var url = new URI("http://localhost").toURL();
var urlConnection = url.openConnection(new Proxy(Proxy.Type.HTTP, new InetSocketAddress(0)));
assert urlConnection != null;
}

@EntitlementTest(expectedAccess = PLUGINS)
static void urlOpenStream() throws Exception {
try {
URI.create("http://127.0.0.1:12345/").toURL().openStream().close();
} catch (java.net.ConnectException e) {
// It's OK, it means we passed entitlement checks, and we tried to connect
}
}

@EntitlementTest(expectedAccess = PLUGINS)
static void urlGetContent() throws Exception {
try {
URI.create("http://127.0.0.1:12345/").toURL().getContent();
} catch (java.net.ConnectException e) {
// It's OK, it means we passed entitlement checks, and we tried to connect
}
}

@EntitlementTest(expectedAccess = PLUGINS)
static void urlGetContentWithClasses() throws Exception {
try {
URI.create("http://127.0.0.1:12345/").toURL().getContent(new Class<?>[] { String.class });
} catch (java.net.ConnectException e) {
// It's OK, it means we passed entitlement checks, and we tried to connect
}
}

@EntitlementTest(expectedAccess = PLUGINS)
static void baseUrlConnectionGetContentLength() throws Exception {
withPlainNetworkConnection(URLConnection::getContentLength);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void sunHttpConnectionGetContentLength() throws Exception {
withJdkHttpConnection(URLConnection::getContentLength);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void baseUrlConnectionGetContentType() throws Exception {
withPlainNetworkConnection(URLConnection::getContentType);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void sunHttpConnectionGetContentType() throws Exception {
withJdkHttpConnection(URLConnection::getContentType);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void baseUrlConnectionGetContentEncoding() throws Exception {
withPlainNetworkConnection(URLConnection::getContentEncoding);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void sunHttpConnectionGetContentEncoding() throws Exception {
withJdkHttpConnection(URLConnection::getContentEncoding);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void baseUrlConnectionGetExpiration() throws Exception {
withPlainNetworkConnection(URLConnection::getExpiration);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void sunHttpConnectionGetExpiration() throws Exception {
withJdkHttpConnection(URLConnection::getExpiration);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void baseUrlConnectionGetDate() throws Exception {
withPlainNetworkConnection(URLConnection::getDate);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void sunHttpConnectionGetDate() throws Exception {
withJdkHttpConnection(URLConnection::getDate);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void baseUrlConnectionGetLastModified() throws Exception {
withPlainNetworkConnection(URLConnection::getLastModified);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void sunHttpConnectionGetLastModified() throws Exception {
withJdkHttpConnection(URLConnection::getLastModified);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void baseUrlConnectionGetHeaderFieldInt() throws Exception {
withPlainNetworkConnection(conn -> conn.getHeaderFieldInt("field", 0));
}

@EntitlementTest(expectedAccess = PLUGINS)
static void sunHttpConnectionGetHeaderFieldInt() throws Exception {
withJdkHttpConnection(conn -> conn.getHeaderFieldInt("field", 0));
}

@EntitlementTest(expectedAccess = PLUGINS)
static void baseUrlConnectionGetHeaderFieldLong() throws Exception {
withPlainNetworkConnection(conn -> conn.getHeaderFieldLong("field", 0));
}

@EntitlementTest(expectedAccess = PLUGINS)
static void sunHttpConnectionGetHeaderFieldLong() throws Exception {
withJdkHttpConnection(conn -> conn.getHeaderFieldLong("field", 0));
}

@EntitlementTest(expectedAccess = PLUGINS)
static void baseUrlConnectionGetContent() throws Exception {
withPlainNetworkConnection(URLConnection::getContent);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void sunHttpConnectionGetContent() throws Exception {
withJdkHttpConnection(URLConnection::getContent);
}

@EntitlementTest(expectedAccess = PLUGINS)
static void baseUrlConnectionGetContentWithClasses() throws Exception {
withPlainNetworkConnection(conn -> conn.getContent(new Class<?>[] { String.class }));
}

@EntitlementTest(expectedAccess = PLUGINS)
static void sunHttpConnectionGetContentWithClasses() throws Exception {
withJdkHttpConnection(conn -> conn.getContent(new Class<?>[] { String.class }));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@ class EntitlementsTestRule implements TestRule {
// entitlements that test methods may use, see EntitledActions
private static final PolicyBuilder ENTITLED_POLICY = (builder, tempDir) -> {
builder.value("manage_threads");
builder.value("outbound_network");
builder.value(
Map.of(
"files",
Expand Down
Loading