Ban write access to system properties

* Forbid System.setProperties & co in forbidden APIs.
* Ban property write access at runtime with security manager.

Plugins that need to modify system properties will need to request permission in their plugin-security.policy
This commit is contained in:
Robert Muir 2015-11-21 22:33:06 -05:00
parent 335e7fca24
commit 30529c008d
40 changed files with 665 additions and 490 deletions

View File

@ -105,3 +105,10 @@ java.lang.Thread#getAllStackTraces()
java.lang.System#exit(int)
java.lang.Runtime#exit(int)
java.lang.Runtime#halt(int)
@defaultMessage Treat system properties as immutable
java.lang.System#setProperties(java.util.Properties)
java.lang.System#setProperty(java.lang.String,java.lang.String)
java.lang.System#clearProperty(java.lang.String)
java.lang.System#getProperties() @ Use BootstrapInfo.getSystemProperties for a read-only view

View File

@ -138,6 +138,7 @@ final class Bootstrap {
// Force probes to be loaded
ProcessProbe.getInstance();
OsProbe.getInstance();
JvmInfo.jvmInfo();
}
private void setup(boolean addShutdownHook, Settings settings, Environment environment) throws Exception {
@ -230,13 +231,20 @@ final class Bootstrap {
}
}
/** Set the system property before anything has a chance to trigger its use */
// TODO: why? is it just a bad default somewhere? or is it some BS around 'but the client' garbage <-- my guess
@SuppressForbidden(reason = "sets logger prefix on initialization")
static void initLoggerPrefix() {
System.setProperty("es.logger.prefix", "");
}
/**
* This method is invoked by {@link Elasticsearch#main(String[])}
* to startup elasticsearch.
*/
static void init(String[] args) throws Throwable {
// Set the system property before anything has a chance to trigger its use
System.setProperty("es.logger.prefix", "");
initLoggerPrefix();
BootstrapCLIParser bootstrapCLIParser = new BootstrapCLIParser();
CliTool.ExitStatus status = bootstrapCLIParser.execute(args);

View File

@ -23,6 +23,7 @@ import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.Option;
import org.elasticsearch.Build;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.cli.CliTool;
import org.elasticsearch.common.cli.CliToolConfig;
import org.elasticsearch.common.cli.Terminal;
@ -100,6 +101,8 @@ final class BootstrapCLIParser extends CliTool {
.stopAtNonOption(true) // needed to parse the --foo.bar options, so this parser must be lenient
.build();
// TODO: don't use system properties as a way to do this, its horrible...
@SuppressForbidden(reason = "Sets system properties passed as CLI parameters")
public static Command parse(Terminal terminal, CommandLine cli) {
if (cli.hasOption("V")) {
return Version.parse(terminal, cli);

View File

@ -19,9 +19,15 @@
package org.elasticsearch.bootstrap;
import org.elasticsearch.common.SuppressForbidden;
import java.util.Dictionary;
import java.util.Enumeration;
/**
* Exposes system startup information
*/
@SuppressForbidden(reason = "exposes read-only view of system properties")
public final class BootstrapInfo {
/** no instantiation */
@ -57,4 +63,61 @@ public final class BootstrapInfo {
* This is not a full URL, just a path.
*/
public static final String UNTRUSTED_CODEBASE = "/untrusted";
// create a view of sysprops map that does not allow modifications
// this must be done this way (e.g. versus an actual typed map), because
// some test methods still change properties, so whitelisted changes must
// be reflected in this this view.
private static final Dictionary<Object,Object> SYSTEM_PROPERTIES;
static {
final Dictionary<Object,Object> sysprops = System.getProperties();
SYSTEM_PROPERTIES = new Dictionary<Object,Object>() {
@Override
public int size() {
return sysprops.size();
}
@Override
public boolean isEmpty() {
return sysprops.isEmpty();
}
@Override
public Enumeration<Object> keys() {
return sysprops.keys();
}
@Override
public Enumeration<Object> elements() {
return sysprops.elements();
}
@Override
public Object get(Object key) {
return sysprops.get(key);
}
@Override
public Object put(Object key, Object value) {
throw new UnsupportedOperationException("treat system properties as immutable");
}
@Override
public Object remove(Object key) {
throw new UnsupportedOperationException("treat system properties as immutable");
}
};
}
/**
* Returns a read-only view of all system properties
*/
public static Dictionary<Object,Object> getSystemProperties() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPropertyAccess("*");
}
return SYSTEM_PROPERTIES;
}
}

View File

@ -21,6 +21,7 @@ package org.elasticsearch.common.logging.log4j;
import org.apache.log4j.PropertyConfigurator;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.bootstrap.BootstrapInfo;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.env.Environment;
@ -106,8 +107,8 @@ public class LogConfigurator {
resolveConfig(environment, settingsBuilder);
}
settingsBuilder
.putProperties("elasticsearch.", System.getProperties())
.putProperties("es.", System.getProperties());
.putProperties("elasticsearch.", BootstrapInfo.getSystemProperties())
.putProperties("es.", BootstrapInfo.getSystemProperties());
// add custom settings after config was added so that they are not overwritten by config
settingsBuilder.put(settings);
settingsBuilder.replacePropertyPlaceholders();

View File

@ -46,13 +46,14 @@ import java.nio.file.Path;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Dictionary;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Objects;
import java.util.Set;
import java.util.SortedMap;
import java.util.TreeMap;
@ -1028,9 +1029,9 @@ public final class Settings implements ToXContent {
/**
* Sets all the provided settings.
*/
public Builder put(Properties properties) {
for (Map.Entry entry : properties.entrySet()) {
map.put((String) entry.getKey(), (String) entry.getValue());
public Builder put(Dictionary<Object,Object> properties) {
for (Object key : Collections.list(properties.keys())) {
map.put(Objects.toString(key), Objects.toString(properties.get(key)));
}
return this;
}
@ -1096,10 +1097,10 @@ public final class Settings implements ToXContent {
* @param properties The properties to put
* @return The builder
*/
public Builder putProperties(String prefix, Properties properties) {
for (Object key1 : properties.keySet()) {
String key = (String) key1;
String value = properties.getProperty(key);
public Builder putProperties(String prefix, Dictionary<Object,Object> properties) {
for (Object key1 : Collections.list(properties.keys())) {
String key = Objects.toString(key1);
String value = Objects.toString(properties.get(key));
if (key.startsWith(prefix)) {
map.put(key.substring(prefix.length()), value);
}
@ -1114,10 +1115,10 @@ public final class Settings implements ToXContent {
* @param properties The properties to put
* @return The builder
*/
public Builder putProperties(String prefix, Properties properties, String[] ignorePrefixes) {
for (Object key1 : properties.keySet()) {
String key = (String) key1;
String value = properties.getProperty(key);
public Builder putProperties(String prefix, Dictionary<Object,Object> properties, String[] ignorePrefixes) {
for (Object key1 : Collections.list(properties.keys())) {
String key = Objects.toString(key1);
String value = Objects.toString(properties.get(key));
if (key.startsWith(prefix)) {
boolean ignore = false;
for (String ignorePrefix : ignorePrefixes) {

View File

@ -20,6 +20,7 @@
package org.elasticsearch.http.netty;
import org.elasticsearch.common.Booleans;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.inject.Inject;
import org.elasticsearch.common.netty.NettyUtils;
@ -138,6 +139,8 @@ public class NettyHttpServerTransport extends AbstractLifecycleComponent<HttpSer
protected volatile HttpServerAdapter httpServerAdapter;
@Inject
@SuppressForbidden(reason = "sets org.jboss.netty.epollBugWorkaround based on netty.epollBugWorkaround")
// TODO: why be confusing like this? just let the user do it with the netty parameter instead!
public NettyHttpServerTransport(Settings settings, NetworkService networkService, BigArrays bigArrays) {
super(settings);
this.networkService = networkService;

View File

@ -30,6 +30,7 @@ import org.elasticsearch.common.xcontent.XContentBuilderString;
import java.io.IOException;
import java.lang.management.*;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@ -57,7 +58,7 @@ public class JvmInfo implements Streamable, ToXContent {
JvmInfo info = new JvmInfo();
info.pid = pid;
info.startTime = runtimeMXBean.getStartTime();
info.version = runtimeMXBean.getSystemProperties().get("java.version");
info.version = System.getProperty("java.version");
info.vmName = runtimeMXBean.getVmName();
info.vmVendor = runtimeMXBean.getVmVendor();
info.vmVersion = runtimeMXBean.getVmVersion();
@ -84,7 +85,7 @@ public class JvmInfo implements Streamable, ToXContent {
}
}
info.classPath = runtimeMXBean.getClassPath();
info.systemProperties = runtimeMXBean.getSystemProperties();
info.systemProperties = Collections.unmodifiableMap(runtimeMXBean.getSystemProperties());
List<GarbageCollectorMXBean> gcMxBeans = ManagementFactory.getGarbageCollectorMXBeans();
info.gcCollectors = new String[gcMxBeans.size()];
@ -104,6 +105,11 @@ public class JvmInfo implements Streamable, ToXContent {
}
public static JvmInfo jvmInfo() {
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new ManagementPermission("monitor"));
sm.checkPropertyAccess("*");
}
return INSTANCE;
}

View File

@ -20,6 +20,8 @@
package org.elasticsearch.node.internal;
import java.nio.charset.StandardCharsets;
import org.elasticsearch.bootstrap.BootstrapInfo;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.common.Booleans;
import org.elasticsearch.common.Strings;
@ -125,11 +127,11 @@ public class InternalSettingsPreparer {
if (useSystemProperties(input)) {
if (loadDefaults) {
for (String prefix : PROPERTY_DEFAULTS_PREFIXES) {
output.putProperties(prefix, System.getProperties());
output.putProperties(prefix, BootstrapInfo.getSystemProperties());
}
}
for (String prefix : PROPERTY_PREFIXES) {
output.putProperties(prefix, System.getProperties(), PROPERTY_DEFAULTS_PREFIXES);
output.putProperties(prefix, BootstrapInfo.getSystemProperties(), PROPERTY_DEFAULTS_PREFIXES);
}
}
output.replacePropertyPlaceholders();

View File

@ -24,6 +24,7 @@ import org.elasticsearch.Version;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.Booleans;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.bytes.ReleasablePagedBytesReference;
import org.elasticsearch.common.component.AbstractLifecycleComponent;
import org.elasticsearch.common.compress.CompressorFactory;
@ -205,6 +206,8 @@ public class NettyTransport extends AbstractLifecycleComponent<Transport> implem
final ScheduledPing scheduledPing;
@Inject
@SuppressForbidden(reason = "sets org.jboss.netty.epollBugWorkaround based on netty.epollBugWorkaround")
// TODO: why be confusing like this? just let the user do it with the netty parameter instead!
public NettyTransport(Settings settings, ThreadPool threadPool, NetworkService networkService, BigArrays bigArrays, Version version, NamedWriteableRegistry namedWriteableRegistry) {
super(settings);
this.threadPool = threadPool;

View File

@ -48,8 +48,37 @@ grant {
// Allow connecting to the internet anywhere
permission java.net.SocketPermission "*", "accept,connect,resolve";
// Allow read/write to all system properties
permission java.util.PropertyPermission "*", "read,write";
// Allow read access to all system properties
permission java.util.PropertyPermission "*", "read";
// TODO: clean all these property writes up, and don't allow any more in. these are all bogus!
// LuceneTestCase randomization (locale/timezone/cpus/ssd)
// TODO: put these in doPrivileged and move these to test-framework.policy
permission java.util.PropertyPermission "user.language", "write";
permission java.util.PropertyPermission "user.timezone", "write";
permission java.util.PropertyPermission "lucene.cms.override_core_count", "write";
permission java.util.PropertyPermission "lucene.cms.override_spins", "write";
// messiness in LuceneTestCase: do the above, or clean this up, or simply allow to fail if its denied
permission java.util.PropertyPermission "solr.solr.home", "write";
permission java.util.PropertyPermission "solr.data.dir", "write";
permission java.util.PropertyPermission "solr.directoryFactory", "write";
// set by ESTestCase to improve test reproducibility
// TODO: set this with gradle or some other way that repros with seed?
permission java.util.PropertyPermission "es.processors.override", "write";
// set by CLIToolTestCase
// TODO: do this differently? or test commandline tools differently?
permission java.util.PropertyPermission "es.default.path.home", "write";
// TODO: these simply trigger a noisy warning if its unable to clear the properties
// fix that in randomizedtesting
permission java.util.PropertyPermission "junit4.childvm.count", "write";
permission java.util.PropertyPermission "junit4.childvm.id", "write";
// set by NettyTransport/NettyHttpServerTransport based on another parameter
// TODO: look into this and decide if users should simply set the actual sysprop?!
permission java.util.PropertyPermission "org.jboss.netty.epollBugWorkaround", "write";
// needed by lucene SPI currently
permission java.lang.RuntimePermission "getClassLoader";

View File

@ -23,6 +23,7 @@ import org.elasticsearch.action.bulk.BulkRequestBuilder;
import org.elasticsearch.action.support.IndicesOptions;
import org.elasticsearch.bootstrap.BootstrapForTesting;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.TimeValue;
import org.elasticsearch.common.xcontent.XContentBuilder;
@ -36,6 +37,7 @@ import static org.elasticsearch.node.NodeBuilder.nodeBuilder;
/**
*/
@SuppressForbidden(reason = "not really source code or a test")
public class ManyMappingsBenchmark {
private static final String MAPPING = "{\n" +

View File

@ -19,10 +19,12 @@
package org.elasticsearch.benchmark.monitor.os;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.monitor.os.OsProbe;
@SuppressForbidden(reason = "not really source code or a test")
public class OsProbeBenchmark {
private static final int ITERATIONS = 100_000;

View File

@ -23,6 +23,7 @@ import org.elasticsearch.bootstrap.BootstrapForTesting;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.cluster.routing.allocation.decider.DiskThresholdDecider;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.logging.ESLogger;
import org.elasticsearch.common.logging.ESLoggerFactory;
import org.elasticsearch.common.settings.Settings;
@ -46,6 +47,7 @@ import static org.elasticsearch.node.NodeBuilder.nodeBuilder;
/**
*
*/
@SuppressForbidden(reason = "not really source code or a test")
public class ReplicaRecoveryBenchmark {
private static final String INDEX_NAME = "index";

View File

@ -29,6 +29,7 @@ import org.elasticsearch.action.search.SearchResponse;
import org.elasticsearch.benchmark.search.aggregations.TermsAggregationSearchBenchmark.StatsResult;
import org.elasticsearch.bootstrap.BootstrapForTesting;
import org.elasticsearch.client.Client;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.unit.ByteSizeValue;
import org.elasticsearch.common.unit.SizeValue;
@ -51,6 +52,7 @@ import static org.elasticsearch.node.NodeBuilder.nodeBuilder;
/**
*
*/
@SuppressForbidden(reason = "not really source code or a test")
public class GlobalOrdinalsBenchmark {
private static final String INDEX_NAME = "index";

View File

@ -74,18 +74,6 @@ public class JarHellTests extends ESTestCase {
}
}
public void testBootclasspathLeniency() throws Exception {
Path dir = createTempDir();
String previousJavaHome = System.getProperty("java.home");
System.setProperty("java.home", dir.toString());
URL[] jars = {makeJar(dir, "foo.jar", null, "DuplicateClass.class"), makeJar(dir, "bar.jar", null, "DuplicateClass.class")};
try {
JarHell.checkJarHell(jars);
} finally {
System.setProperty("java.home", previousJavaHome);
}
}
public void testDuplicateClasspathLeniency() throws Exception {
Path dir = createTempDir();
URL jar = makeJar(dir, "foo.jar", null, "Foo.class");
@ -179,40 +167,6 @@ public class JarHellTests extends ESTestCase {
}
}
public void testRequiredJDKVersionIsOK() throws Exception {
Path dir = createTempDir();
String previousJavaVersion = System.getProperty("java.specification.version");
System.setProperty("java.specification.version", "1.7");
Manifest manifest = new Manifest();
Attributes attributes = manifest.getMainAttributes();
attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
attributes.put(new Attributes.Name("X-Compile-Target-JDK"), "1.7");
URL[] jars = {makeJar(dir, "foo.jar", manifest, "Foo.class")};
try {
JarHell.checkJarHell(jars);
} finally {
System.setProperty("java.specification.version", previousJavaVersion);
}
}
public void testBadJDKVersionProperty() throws Exception {
Path dir = createTempDir();
String previousJavaVersion = System.getProperty("java.specification.version");
System.setProperty("java.specification.version", "bogus");
Manifest manifest = new Manifest();
Attributes attributes = manifest.getMainAttributes();
attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
attributes.put(new Attributes.Name("X-Compile-Target-JDK"), "1.7");
URL[] jars = {makeJar(dir, "foo.jar", manifest, "Foo.class")};
try {
JarHell.checkJarHell(jars);
} finally {
System.setProperty("java.specification.version", previousJavaVersion);
}
}
public void testBadJDKVersionInJar() throws Exception {
Path dir = createTempDir();
Manifest manifest = new Manifest();

View File

@ -19,119 +19,14 @@
package org.elasticsearch.bootstrap;
import org.apache.lucene.util.Constants;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase;
import java.io.FilePermission;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.util.Set;
public class SecurityTests extends ESTestCase {
/** test generated permissions */
public void testGeneratedPermissions() throws Exception {
Path path = createTempDir();
// make a fake ES home and ensure we only grant permissions to that.
Path esHome = path.resolve("esHome");
Settings.Builder settingsBuilder = Settings.builder();
settingsBuilder.put("path.home", esHome.toString());
Settings settings = settingsBuilder.build();
Path fakeTmpDir = createTempDir();
String realTmpDir = System.getProperty("java.io.tmpdir");
Permissions permissions;
try {
System.setProperty("java.io.tmpdir", fakeTmpDir.toString());
Environment environment = new Environment(settings);
permissions = Security.createPermissions(environment);
} finally {
System.setProperty("java.io.tmpdir", realTmpDir);
}
// the fake es home
assertNoPermissions(esHome, permissions);
// its parent
assertNoPermissions(esHome.getParent(), permissions);
// some other sibling
assertNoPermissions(esHome.getParent().resolve("other"), permissions);
// double check we overwrote java.io.tmpdir correctly for the test
assertNoPermissions(PathUtils.get(realTmpDir), permissions);
}
/** test generated permissions for all configured paths */
public void testEnvironmentPaths() throws Exception {
Path path = createTempDir();
// make a fake ES home and ensure we only grant permissions to that.
Path esHome = path.resolve("esHome");
Settings.Builder settingsBuilder = Settings.builder();
settingsBuilder.put("path.home", esHome.resolve("home").toString());
settingsBuilder.put("path.conf", esHome.resolve("conf").toString());
settingsBuilder.put("path.scripts", esHome.resolve("scripts").toString());
settingsBuilder.put("path.plugins", esHome.resolve("plugins").toString());
settingsBuilder.putArray("path.data", esHome.resolve("data1").toString(), esHome.resolve("data2").toString());
settingsBuilder.put("path.shared_data", esHome.resolve("custom").toString());
settingsBuilder.put("path.logs", esHome.resolve("logs").toString());
settingsBuilder.put("pidfile", esHome.resolve("test.pid").toString());
Settings settings = settingsBuilder.build();
Path fakeTmpDir = createTempDir();
String realTmpDir = System.getProperty("java.io.tmpdir");
Permissions permissions;
Environment environment;
try {
System.setProperty("java.io.tmpdir", fakeTmpDir.toString());
environment = new Environment(settings);
permissions = Security.createPermissions(environment);
} finally {
System.setProperty("java.io.tmpdir", realTmpDir);
}
// the fake es home
assertNoPermissions(esHome, permissions);
// its parent
assertNoPermissions(esHome.getParent(), permissions);
// some other sibling
assertNoPermissions(esHome.getParent().resolve("other"), permissions);
// double check we overwrote java.io.tmpdir correctly for the test
assertNoPermissions(PathUtils.get(realTmpDir), permissions);
// check that all directories got permissions:
// bin file: ro
assertExactPermissions(new FilePermission(environment.binFile().toString(), "read,readlink"), permissions);
// lib file: ro
assertExactPermissions(new FilePermission(environment.libFile().toString(), "read,readlink"), permissions);
// config file: ro
assertExactPermissions(new FilePermission(environment.configFile().toString(), "read,readlink"), permissions);
// scripts file: ro
assertExactPermissions(new FilePermission(environment.scriptsFile().toString(), "read,readlink"), permissions);
// plugins: ro
assertExactPermissions(new FilePermission(environment.pluginsFile().toString(), "read,readlink"), permissions);
// data paths: r/w
for (Path dataPath : environment.dataFiles()) {
assertExactPermissions(new FilePermission(dataPath.toString(), "read,readlink,write,delete"), permissions);
}
for (Path dataPath : environment.dataWithClusterFiles()) {
assertExactPermissions(new FilePermission(dataPath.toString(), "read,readlink,write,delete"), permissions);
}
assertExactPermissions(new FilePermission(environment.sharedDataFile().toString(), "read,readlink,write,delete"), permissions);
// logs: r/w
assertExactPermissions(new FilePermission(environment.logsFile().toString(), "read,readlink,write,delete"), permissions);
// temp dir: r/w
assertExactPermissions(new FilePermission(fakeTmpDir.toString(), "read,readlink,write,delete"), permissions);
// PID file: delete only (for the shutdown hook)
assertExactPermissions(new FilePermission(environment.pidFile().toString(), "delete"), permissions);
}
public void testEnsureExists() throws IOException {
Path p = createTempDir();
@ -163,43 +58,6 @@ public class SecurityTests extends ESTestCase {
} catch (IOException expected) {}
}
public void testEnsureSymlink() throws IOException {
Path p = createTempDir();
Path exists = p.resolve("exists");
Files.createDirectory(exists);
// symlink
Path linkExists = p.resolve("linkExists");
try {
Files.createSymbolicLink(linkExists, exists);
} catch (UnsupportedOperationException | IOException e) {
assumeNoException("test requires filesystem that supports symbolic links", e);
} catch (SecurityException e) {
assumeNoException("test cannot create symbolic links with security manager enabled", e);
}
Security.ensureDirectoryExists(linkExists);
Files.createTempFile(linkExists, null, null);
}
public void testEnsureBrokenSymlink() throws IOException {
Path p = createTempDir();
// broken symlink
Path brokenLink = p.resolve("brokenLink");
try {
Files.createSymbolicLink(brokenLink, p.resolve("nonexistent"));
} catch (UnsupportedOperationException | IOException e) {
assumeNoException("test requires filesystem that supports symbolic links", e);
} catch (SecurityException e) {
assumeNoException("test cannot create symbolic links with security manager enabled", e);
}
try {
Security.ensureDirectoryExists(brokenLink);
fail("didn't get expected exception");
} catch (IOException expected) {}
}
/** can't execute processes */
public void testProcessExecution() throws Exception {
assumeTrue("test requires security manager", System.getSecurityManager() != null);
@ -208,61 +66,4 @@ public class SecurityTests extends ESTestCase {
fail("didn't get expected exception");
} catch (SecurityException expected) {}
}
/** When a configured dir is a symlink, test that permissions work on link target */
public void testSymlinkPermissions() throws IOException {
// see https://github.com/elastic/elasticsearch/issues/12170
assumeFalse("windows does not automatically grant permission to the target of symlinks", Constants.WINDOWS);
Path dir = createTempDir();
Path target = dir.resolve("target");
Files.createDirectory(target);
// symlink
Path link = dir.resolve("link");
try {
Files.createSymbolicLink(link, target);
} catch (UnsupportedOperationException | IOException e) {
assumeNoException("test requires filesystem that supports symbolic links", e);
} catch (SecurityException e) {
assumeNoException("test cannot create symbolic links with security manager enabled", e);
}
Permissions permissions = new Permissions();
Security.addPath(permissions, "testing", link, "read");
assertExactPermissions(new FilePermission(link.toString(), "read"), permissions);
assertExactPermissions(new FilePermission(link.resolve("foo").toString(), "read"), permissions);
assertExactPermissions(new FilePermission(target.toString(), "read"), permissions);
assertExactPermissions(new FilePermission(target.resolve("foo").toString(), "read"), permissions);
}
/**
* checks exact file permissions, meaning those and only those for that path.
*/
static void assertExactPermissions(FilePermission expected, PermissionCollection actual) {
String target = expected.getName(); // see javadocs
Set<String> permissionSet = asSet(expected.getActions().split(","));
boolean read = permissionSet.remove("read");
boolean readlink = permissionSet.remove("readlink");
boolean write = permissionSet.remove("write");
boolean delete = permissionSet.remove("delete");
boolean execute = permissionSet.remove("execute");
assertTrue("unrecognized permission: " + permissionSet, permissionSet.isEmpty());
assertEquals(read, actual.implies(new FilePermission(target, "read")));
assertEquals(readlink, actual.implies(new FilePermission(target, "readlink")));
assertEquals(write, actual.implies(new FilePermission(target, "write")));
assertEquals(delete, actual.implies(new FilePermission(target, "delete")));
assertEquals(execute, actual.implies(new FilePermission(target, "execute")));
}
/**
* checks that this path has no permissions
*/
static void assertNoPermissions(Path path, PermissionCollection actual) {
String target = path.toString();
assertFalse(actual.implies(new FilePermission(target, "read")));
assertFalse(actual.implies(new FilePermission(target, "readlink")));
assertFalse(actual.implies(new FilePermission(target, "write")));
assertFalse(actual.implies(new FilePermission(target, "delete")));
assertFalse(actual.implies(new FilePermission(target, "execute")));
}
}

View File

@ -67,25 +67,23 @@ public class SettingsTests extends ESTestCase {
}
public void testReplacePropertiesPlaceholderSystemProperty() {
System.setProperty("sysProp1", "sysVal1");
try {
Settings settings = settingsBuilder()
.put("setting1", "${sysProp1}")
.replacePropertyPlaceholders()
.build();
assertThat(settings.get("setting1"), equalTo("sysVal1"));
} finally {
System.clearProperty("sysProp1");
}
String value = System.getProperty("java.home");
assertFalse(value.isEmpty());
Settings settings = settingsBuilder()
.put("setting1", "${sysProp1:defaultVal1}")
.put("setting1", "${java.home}")
.replacePropertyPlaceholders()
.build();
assertThat(settings.get("setting1"), equalTo(value));
assertNull(System.getProperty("_test_property_should_not_exist"));
settings = settingsBuilder()
.put("setting1", "${_test_property_should_not_exist:defaultVal1}")
.replacePropertyPlaceholders()
.build();
assertThat(settings.get("setting1"), equalTo("defaultVal1"));
settings = settingsBuilder()
.put("setting1", "${sysProp1:}")
.put("setting1", "${_test_property_should_not_exist:}")
.replacePropertyPlaceholders()
.build();
assertThat(settings.get("setting1"), is(nullValue()));

View File

@ -22,7 +22,6 @@ package org.elasticsearch.node.internal;
import org.elasticsearch.cluster.ClusterName;
import org.elasticsearch.common.cli.CliToolTestCase;
import org.elasticsearch.common.cli.Terminal;
import org.elasticsearch.common.collect.Tuple;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.env.Environment;
@ -35,9 +34,7 @@ import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;
import static org.elasticsearch.common.settings.Settings.settingsBuilder;
@ -45,38 +42,8 @@ import static org.hamcrest.Matchers.*;
public class InternalSettingsPreparerTests extends ESTestCase {
Map<String, String> savedProperties = new HashMap<>();
Settings baseEnvSettings;
@Before
public void saveSettingsSystemProperties() {
// clear out any properties the settings preparer may look for
savedProperties.clear();
for (Object propObj : System.getProperties().keySet()) {
String property = (String)propObj;
// NOTE: these prefixes are prefixes of the defaults, so both are handled here
for (String prefix : InternalSettingsPreparer.PROPERTY_PREFIXES) {
if (property.startsWith(prefix)) {
savedProperties.put(property, System.getProperty(property));
}
}
}
String name = System.getProperty("name");
if (name != null) {
savedProperties.put("name", name);
}
for (String property : savedProperties.keySet()) {
System.clearProperty(property);
}
}
@After
public void restoreSettingsSystemProperties() {
for (Map.Entry<String, String> property : savedProperties.entrySet()) {
System.setProperty(property.getKey(), property.getValue());
}
}
@Before
public void createBaseEnvSettings() {
baseEnvSettings = settingsBuilder()
@ -93,13 +60,13 @@ public class InternalSettingsPreparerTests extends ESTestCase {
Settings settings = InternalSettingsPreparer.prepareSettings(Settings.EMPTY);
assertNotNull(settings.get("name")); // a name was set
assertNotNull(settings.get(ClusterName.SETTING)); // a cluster name was set
assertEquals(settings.toString(), 2, settings.names().size());
int size = settings.names().size();
Environment env = InternalSettingsPreparer.prepareEnvironment(baseEnvSettings, null);
settings = env.settings();
assertNotNull(settings.get("name")); // a name was set
assertNotNull(settings.get(ClusterName.SETTING)); // a cluster name was set
assertEquals(settings.toString(), 3 /* path.home is in the base settings */, settings.names().size());
assertEquals(settings.toString(), size + 1 /* path.home is in the base settings */, settings.names().size());
String home = baseEnvSettings.get("path.home");
String configDir = env.configFile().toString();
assertTrue(configDir, configDir.startsWith(home));
@ -112,30 +79,6 @@ public class InternalSettingsPreparerTests extends ESTestCase {
assertEquals(ClusterName.DEFAULT.value(), settings.get(ClusterName.SETTING));
}
public void testIgnoreSystemProperties() {
try {
System.setProperty("es.node.zone", "foo");
Settings settings = settingsBuilder()
.put("node.zone", "bar")
.put(baseEnvSettings)
.build();
Environment env = InternalSettingsPreparer.prepareEnvironment(settings, null);
// Should use setting from the system property
assertThat(env.settings().get("node.zone"), equalTo("foo"));
settings = settingsBuilder()
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING, true)
.put("node.zone", "bar")
.put(baseEnvSettings)
.build();
env = InternalSettingsPreparer.prepareEnvironment(settings, null);
// Should use setting from the system property
assertThat(env.settings().get("node.zone"), equalTo("bar"));
} finally {
System.clearProperty("es.node.zone");
}
}
public void testReplacePromptPlaceholders() {
final List<String> replacedSecretProperties = new ArrayList<>();
final List<String> replacedTextProperties = new ArrayList<>();
@ -205,74 +148,6 @@ public class InternalSettingsPreparerTests extends ESTestCase {
}
}
public void testNameSettingsPreference() {
try {
System.setProperty("name", "sys-prop-name");
// Test system property overrides node.name
Settings settings = settingsBuilder()
.put("node.name", "node-name")
.put(baseEnvSettings)
.build();
Environment env = InternalSettingsPreparer.prepareEnvironment(settings, null);
assertThat(env.settings().get("name"), equalTo("sys-prop-name"));
// test name in settings overrides sys prop and node.name
settings = settingsBuilder()
.put("name", "name-in-settings")
.put("node.name", "node-name")
.put(baseEnvSettings)
.build();
env = InternalSettingsPreparer.prepareEnvironment(settings, null);
assertThat(env.settings().get("name"), equalTo("name-in-settings"));
// test only node.name in settings
System.clearProperty("name");
settings = settingsBuilder()
.put("node.name", "node-name")
.put(baseEnvSettings)
.build();
env = InternalSettingsPreparer.prepareEnvironment(settings, null);
assertThat(env.settings().get("name"), equalTo("node-name"));
// test no name at all results in name being set
env = InternalSettingsPreparer.prepareEnvironment(baseEnvSettings, null);
assertThat(env.settings().get("name"), not("name-in-settings"));
assertThat(env.settings().get("name"), not("sys-prop-name"));
assertThat(env.settings().get("name"), not("node-name"));
assertThat(env.settings().get("name"), notNullValue());
} finally {
System.clearProperty("name");
}
}
public void testPromptForNodeNameOnlyPromptsOnce() {
final AtomicInteger counter = new AtomicInteger();
final Terminal terminal = new CliToolTestCase.MockTerminal() {
@Override
public char[] readSecret(String message, Object... args) {
fail("readSecret should never be called by this test");
return null;
}
@Override
public String readText(String message, Object... args) {
int count = counter.getAndIncrement();
return "prompted name " + count;
}
};
System.clearProperty("name");
Settings settings = Settings.builder()
.put(baseEnvSettings)
.put("node.name", InternalSettingsPreparer.TEXT_PROMPT_VALUE)
.build();
Environment env = InternalSettingsPreparer.prepareEnvironment(settings, terminal);
settings = env.settings();
assertThat(counter.intValue(), is(1));
assertThat(settings.get("name"), is("prompted name 0"));
assertThat(settings.get("node.name"), is("prompted name 0"));
}
public void testGarbageIsNotSwallowed() throws IOException {
try {
InputStream garbage = getClass().getResourceAsStream("/config/garbage/garbage.yml");

View File

@ -26,11 +26,6 @@ import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.plugin.discovery.ec2.Ec2DiscoveryPlugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ThirdParty;
import org.junit.After;
import org.junit.Before;
import java.util.HashMap;
import java.util.Map;
/**
* Base class for AWS tests that require credentials.
@ -41,35 +36,6 @@ import java.util.Map;
@ThirdParty
public abstract class AbstractAwsTestCase extends ESIntegTestCase {
/**
* Those properties are set by the AWS SDK v1.9.4 and if not ignored,
* lead to tests failure (see AbstractRandomizedTest#IGNORED_INVARIANT_PROPERTIES)
*/
private static final String[] AWS_INVARIANT_PROPERTIES = {
"com.sun.org.apache.xml.internal.dtm.DTMManager",
"javax.xml.parsers.DocumentBuilderFactory"
};
private Map<String, String> properties = new HashMap<>();
@Before
public void saveProperties() {
for (String p : AWS_INVARIANT_PROPERTIES) {
properties.put(p, System.getProperty(p));
}
}
@After
public void restoreProperties() {
for (String p : AWS_INVARIANT_PROPERTIES) {
if (properties.get(p) != null) {
System.setProperty(p, properties.get(p));
} else {
System.clearProperty(p);
}
}
}
@Override
protected Settings nodeSettings(int nodeOrdinal) {
Settings.Builder settings = Settings.builder()

View File

@ -48,9 +48,6 @@ public class PythonScriptEngineTests extends ESTestCase {
@After
public void close() {
// We need to clear some system properties
System.clearProperty("python.cachedir.skip");
System.clearProperty("python.console.encoding");
se.close();
}

View File

@ -24,7 +24,6 @@ import org.elasticsearch.script.CompiledScript;
import org.elasticsearch.script.ExecutableScript;
import org.elasticsearch.script.ScriptService;
import org.elasticsearch.test.ESTestCase;
import org.junit.After;
import java.util.HashMap;
import java.util.Map;
@ -39,12 +38,6 @@ import static org.hamcrest.Matchers.equalTo;
*
*/
public class PythonScriptMultiThreadedTests extends ESTestCase {
@After
public void close() {
// We need to clear some system properties
System.clearProperty("python.cachedir.skip");
System.clearProperty("python.console.encoding");
}
public void testExecutableNoRuntimeParams() throws Exception {
final PythonScriptEngineService se = new PythonScriptEngineService(Settings.Builder.EMPTY_SETTINGS);

View File

@ -45,9 +45,6 @@ public class PythonSecurityTests extends ESTestCase {
@Override
public void tearDown() throws Exception {
// We need to clear some system properties
System.clearProperty("python.cachedir.skip");
System.clearProperty("python.console.encoding");
se.close();
super.tearDown();
}

View File

@ -20,6 +20,7 @@
package org.elasticsearch.mapper.attachments;
import org.apache.commons.cli.CommandLine;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.bytes.BytesReference;
import org.elasticsearch.common.cli.CliTool;
import org.elasticsearch.common.cli.CliToolConfig;
@ -59,6 +60,7 @@ import static org.elasticsearch.test.StreamsUtils.copyToStringFromClasspath;
* StandaloneRunner -u /tmp/mydoc.pdf
* StandaloneRunner -u /tmp/mydoc.pdf --size 1000000
*/
@SuppressForbidden(reason = "commandline tool")
public class StandaloneRunner extends CliTool {
private static final CliToolConfig CONFIG = CliToolConfig.config("tika", StandaloneRunner.class)

View File

@ -68,8 +68,6 @@ public class VariousDocTests extends AttachmentUnitTestCase {
*/
public void testEncryptedPDFDocument() throws Exception {
assertException("encrypted.pdf", "is encrypted");
// TODO Remove when this will be fixed in Tika. See https://issues.apache.org/jira/browse/TIKA-1548
System.clearProperty("sun.font.fontmanager");
testMapper("encrypted.pdf", true);
}

View File

@ -26,11 +26,6 @@ import org.elasticsearch.common.settings.SettingsException;
import org.elasticsearch.plugin.repository.s3.S3RepositoryPlugin;
import org.elasticsearch.test.ESIntegTestCase;
import org.elasticsearch.test.ESIntegTestCase.ThirdParty;
import org.junit.After;
import org.junit.Before;
import java.util.HashMap;
import java.util.Map;
/**
* Base class for AWS tests that require credentials.
@ -41,35 +36,6 @@ import java.util.Map;
@ThirdParty
public abstract class AbstractAwsTestCase extends ESIntegTestCase {
/**
* Those properties are set by the AWS SDK v1.9.4 and if not ignored,
* lead to tests failure (see AbstractRandomizedTest#IGNORED_INVARIANT_PROPERTIES)
*/
private static final String[] AWS_INVARIANT_PROPERTIES = {
"com.sun.org.apache.xml.internal.dtm.DTMManager",
"javax.xml.parsers.DocumentBuilderFactory"
};
private Map<String, String> properties = new HashMap<>();
@Before
public void saveProperties() {
for (String p : AWS_INVARIANT_PROPERTIES) {
properties.put(p, System.getProperty(p));
}
}
@After
public void restoreProperties() {
for (String p : AWS_INVARIANT_PROPERTIES) {
if (properties.get(p) != null) {
System.setProperty(p, properties.get(p));
} else {
System.clearProperty(p);
}
}
}
@Override
protected Settings nodeSettings(int nodeOrdinal) {
Settings.Builder settings = Settings.builder()

View File

@ -21,6 +21,7 @@ package org.elasticsearch.bootstrap;
import org.elasticsearch.Build;
import org.elasticsearch.Version;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.cli.CliTool.ExitStatus;
import org.elasticsearch.common.cli.CliToolTestCase;
import org.elasticsearch.common.collect.Tuple;
@ -36,6 +37,7 @@ import java.util.Locale;
import static org.elasticsearch.common.cli.CliTool.ExitStatus.*;
import static org.hamcrest.Matchers.*;
@SuppressForbidden(reason = "modifies system properties intentionally")
public class BootstrapCliParserTests extends CliToolTestCase {
private CaptureOutputTerminal terminal = new CaptureOutputTerminal();

View File

@ -0,0 +1,100 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.bootstrap;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.test.ESTestCase;
import java.io.IOException;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.util.jar.Attributes;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
/** Tests for Jarhell that change very important system properties... very evil! */
@SuppressForbidden(reason = "modifies system properties intentionally")
public class EvilJarHellTests extends ESTestCase {
URL makeJar(Path dir, String name, Manifest manifest, String... files) throws IOException {
Path jarpath = dir.resolve(name);
ZipOutputStream out;
if (manifest == null) {
out = new JarOutputStream(Files.newOutputStream(jarpath, StandardOpenOption.CREATE));
} else {
out = new JarOutputStream(Files.newOutputStream(jarpath, StandardOpenOption.CREATE), manifest);
}
for (String file : files) {
out.putNextEntry(new ZipEntry(file));
}
out.close();
return jarpath.toUri().toURL();
}
public void testBootclasspathLeniency() throws Exception {
Path dir = createTempDir();
String previousJavaHome = System.getProperty("java.home");
System.setProperty("java.home", dir.toString());
URL[] jars = {makeJar(dir, "foo.jar", null, "DuplicateClass.class"), makeJar(dir, "bar.jar", null, "DuplicateClass.class")};
try {
JarHell.checkJarHell(jars);
} finally {
System.setProperty("java.home", previousJavaHome);
}
}
public void testRequiredJDKVersionIsOK() throws Exception {
Path dir = createTempDir();
String previousJavaVersion = System.getProperty("java.specification.version");
System.setProperty("java.specification.version", "1.7");
Manifest manifest = new Manifest();
Attributes attributes = manifest.getMainAttributes();
attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
attributes.put(new Attributes.Name("X-Compile-Target-JDK"), "1.7");
URL[] jars = {makeJar(dir, "foo.jar", manifest, "Foo.class")};
try {
JarHell.checkJarHell(jars);
} finally {
System.setProperty("java.specification.version", previousJavaVersion);
}
}
public void testBadJDKVersionProperty() throws Exception {
Path dir = createTempDir();
String previousJavaVersion = System.getProperty("java.specification.version");
System.setProperty("java.specification.version", "bogus");
Manifest manifest = new Manifest();
Attributes attributes = manifest.getMainAttributes();
attributes.put(Attributes.Name.MANIFEST_VERSION, "1.0.0");
attributes.put(new Attributes.Name("X-Compile-Target-JDK"), "1.7");
URL[] jars = {makeJar(dir, "foo.jar", manifest, "Foo.class")};
try {
JarHell.checkJarHell(jars);
} finally {
System.setProperty("java.specification.version", previousJavaVersion);
}
}
}

View File

@ -0,0 +1,230 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.bootstrap;
import org.apache.lucene.util.Constants;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase;
import java.io.FilePermission;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.PermissionCollection;
import java.security.Permissions;
import java.util.Set;
@SuppressForbidden(reason = "modifies system properties and attempts to create symbolic links intentionally")
public class EvilSecurityTests extends ESTestCase {
/** test generated permissions */
public void testGeneratedPermissions() throws Exception {
Path path = createTempDir();
// make a fake ES home and ensure we only grant permissions to that.
Path esHome = path.resolve("esHome");
Settings.Builder settingsBuilder = Settings.builder();
settingsBuilder.put("path.home", esHome.toString());
Settings settings = settingsBuilder.build();
Path fakeTmpDir = createTempDir();
String realTmpDir = System.getProperty("java.io.tmpdir");
Permissions permissions;
try {
System.setProperty("java.io.tmpdir", fakeTmpDir.toString());
Environment environment = new Environment(settings);
permissions = Security.createPermissions(environment);
} finally {
System.setProperty("java.io.tmpdir", realTmpDir);
}
// the fake es home
assertNoPermissions(esHome, permissions);
// its parent
assertNoPermissions(esHome.getParent(), permissions);
// some other sibling
assertNoPermissions(esHome.getParent().resolve("other"), permissions);
// double check we overwrote java.io.tmpdir correctly for the test
assertNoPermissions(PathUtils.get(realTmpDir), permissions);
}
/** test generated permissions for all configured paths */
public void testEnvironmentPaths() throws Exception {
Path path = createTempDir();
// make a fake ES home and ensure we only grant permissions to that.
Path esHome = path.resolve("esHome");
Settings.Builder settingsBuilder = Settings.builder();
settingsBuilder.put("path.home", esHome.resolve("home").toString());
settingsBuilder.put("path.conf", esHome.resolve("conf").toString());
settingsBuilder.put("path.scripts", esHome.resolve("scripts").toString());
settingsBuilder.put("path.plugins", esHome.resolve("plugins").toString());
settingsBuilder.putArray("path.data", esHome.resolve("data1").toString(), esHome.resolve("data2").toString());
settingsBuilder.put("path.shared_data", esHome.resolve("custom").toString());
settingsBuilder.put("path.logs", esHome.resolve("logs").toString());
settingsBuilder.put("pidfile", esHome.resolve("test.pid").toString());
Settings settings = settingsBuilder.build();
Path fakeTmpDir = createTempDir();
String realTmpDir = System.getProperty("java.io.tmpdir");
Permissions permissions;
Environment environment;
try {
System.setProperty("java.io.tmpdir", fakeTmpDir.toString());
environment = new Environment(settings);
permissions = Security.createPermissions(environment);
} finally {
System.setProperty("java.io.tmpdir", realTmpDir);
}
// the fake es home
assertNoPermissions(esHome, permissions);
// its parent
assertNoPermissions(esHome.getParent(), permissions);
// some other sibling
assertNoPermissions(esHome.getParent().resolve("other"), permissions);
// double check we overwrote java.io.tmpdir correctly for the test
assertNoPermissions(PathUtils.get(realTmpDir), permissions);
// check that all directories got permissions:
// bin file: ro
assertExactPermissions(new FilePermission(environment.binFile().toString(), "read,readlink"), permissions);
// lib file: ro
assertExactPermissions(new FilePermission(environment.libFile().toString(), "read,readlink"), permissions);
// config file: ro
assertExactPermissions(new FilePermission(environment.configFile().toString(), "read,readlink"), permissions);
// scripts file: ro
assertExactPermissions(new FilePermission(environment.scriptsFile().toString(), "read,readlink"), permissions);
// plugins: ro
assertExactPermissions(new FilePermission(environment.pluginsFile().toString(), "read,readlink"), permissions);
// data paths: r/w
for (Path dataPath : environment.dataFiles()) {
assertExactPermissions(new FilePermission(dataPath.toString(), "read,readlink,write,delete"), permissions);
}
for (Path dataPath : environment.dataWithClusterFiles()) {
assertExactPermissions(new FilePermission(dataPath.toString(), "read,readlink,write,delete"), permissions);
}
assertExactPermissions(new FilePermission(environment.sharedDataFile().toString(), "read,readlink,write,delete"), permissions);
// logs: r/w
assertExactPermissions(new FilePermission(environment.logsFile().toString(), "read,readlink,write,delete"), permissions);
// temp dir: r/w
assertExactPermissions(new FilePermission(fakeTmpDir.toString(), "read,readlink,write,delete"), permissions);
// PID file: delete only (for the shutdown hook)
assertExactPermissions(new FilePermission(environment.pidFile().toString(), "delete"), permissions);
}
public void testEnsureSymlink() throws IOException {
Path p = createTempDir();
Path exists = p.resolve("exists");
Files.createDirectory(exists);
// symlink
Path linkExists = p.resolve("linkExists");
try {
Files.createSymbolicLink(linkExists, exists);
} catch (UnsupportedOperationException | IOException e) {
assumeNoException("test requires filesystem that supports symbolic links", e);
} catch (SecurityException e) {
assumeNoException("test cannot create symbolic links with security manager enabled", e);
}
Security.ensureDirectoryExists(linkExists);
Files.createTempFile(linkExists, null, null);
}
public void testEnsureBrokenSymlink() throws IOException {
Path p = createTempDir();
// broken symlink
Path brokenLink = p.resolve("brokenLink");
try {
Files.createSymbolicLink(brokenLink, p.resolve("nonexistent"));
} catch (UnsupportedOperationException | IOException e) {
assumeNoException("test requires filesystem that supports symbolic links", e);
} catch (SecurityException e) {
assumeNoException("test cannot create symbolic links with security manager enabled", e);
}
try {
Security.ensureDirectoryExists(brokenLink);
fail("didn't get expected exception");
} catch (IOException expected) {}
}
/** When a configured dir is a symlink, test that permissions work on link target */
public void testSymlinkPermissions() throws IOException {
// see https://github.com/elastic/elasticsearch/issues/12170
assumeFalse("windows does not automatically grant permission to the target of symlinks", Constants.WINDOWS);
Path dir = createTempDir();
Path target = dir.resolve("target");
Files.createDirectory(target);
// symlink
Path link = dir.resolve("link");
try {
Files.createSymbolicLink(link, target);
} catch (UnsupportedOperationException | IOException e) {
assumeNoException("test requires filesystem that supports symbolic links", e);
} catch (SecurityException e) {
assumeNoException("test cannot create symbolic links with security manager enabled", e);
}
Permissions permissions = new Permissions();
Security.addPath(permissions, "testing", link, "read");
assertExactPermissions(new FilePermission(link.toString(), "read"), permissions);
assertExactPermissions(new FilePermission(link.resolve("foo").toString(), "read"), permissions);
assertExactPermissions(new FilePermission(target.toString(), "read"), permissions);
assertExactPermissions(new FilePermission(target.resolve("foo").toString(), "read"), permissions);
}
/**
* checks exact file permissions, meaning those and only those for that path.
*/
static void assertExactPermissions(FilePermission expected, PermissionCollection actual) {
String target = expected.getName(); // see javadocs
Set<String> permissionSet = asSet(expected.getActions().split(","));
boolean read = permissionSet.remove("read");
boolean readlink = permissionSet.remove("readlink");
boolean write = permissionSet.remove("write");
boolean delete = permissionSet.remove("delete");
boolean execute = permissionSet.remove("execute");
assertTrue("unrecognized permission: " + permissionSet, permissionSet.isEmpty());
assertEquals(read, actual.implies(new FilePermission(target, "read")));
assertEquals(readlink, actual.implies(new FilePermission(target, "readlink")));
assertEquals(write, actual.implies(new FilePermission(target, "write")));
assertEquals(delete, actual.implies(new FilePermission(target, "delete")));
assertEquals(execute, actual.implies(new FilePermission(target, "execute")));
}
/**
* checks that this path has no permissions
*/
static void assertNoPermissions(Path path, PermissionCollection actual) {
String target = path.toString();
assertFalse(actual.implies(new FilePermission(target, "read")));
assertFalse(actual.implies(new FilePermission(target, "readlink")));
assertFalse(actual.implies(new FilePermission(target, "write")));
assertFalse(actual.implies(new FilePermission(target, "delete")));
assertFalse(actual.implies(new FilePermission(target, "execute")));
}
}

View File

@ -22,6 +22,7 @@ package org.elasticsearch.common.cli;
import org.apache.commons.cli.CommandLine;
import org.elasticsearch.ElasticsearchException;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.node.internal.InternalSettingsPreparer;
@ -45,6 +46,7 @@ import static org.hamcrest.Matchers.is;
/**
*
*/
@SuppressForbidden(reason = "modifies system properties intentionally")
public class CliToolTests extends CliToolTestCase {
public void testOK() throws Exception {
Terminal terminal = new MockTerminal();

View File

@ -0,0 +1,145 @@
/*
* Licensed to Elasticsearch under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch licenses this file to you under
* the Apache License, Version 2.0 (the "License"); you may
* not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.elasticsearch.node.internal;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
import org.elasticsearch.test.ESTestCase;
import org.junit.After;
import org.junit.Before;
import java.util.HashMap;
import java.util.Map;
import static org.elasticsearch.common.settings.Settings.settingsBuilder;
import static org.hamcrest.Matchers.*;
@SuppressForbidden(reason = "modifies system properties intentionally")
public class EvilInternalSettingsPreparerTests extends ESTestCase {
Map<String, String> savedProperties = new HashMap<>();
Settings baseEnvSettings;
@Before
public void saveSettingsSystemProperties() {
// clear out any properties the settings preparer may look for
savedProperties.clear();
for (Object propObj : System.getProperties().keySet()) {
String property = (String)propObj;
// NOTE: these prefixes are prefixes of the defaults, so both are handled here
for (String prefix : InternalSettingsPreparer.PROPERTY_PREFIXES) {
if (property.startsWith(prefix)) {
savedProperties.put(property, System.getProperty(property));
}
}
}
String name = System.getProperty("name");
if (name != null) {
savedProperties.put("name", name);
}
for (String property : savedProperties.keySet()) {
System.clearProperty(property);
}
}
@After
public void restoreSettingsSystemProperties() {
for (Map.Entry<String, String> property : savedProperties.entrySet()) {
System.setProperty(property.getKey(), property.getValue());
}
}
@Before
public void createBaseEnvSettings() {
baseEnvSettings = settingsBuilder()
.put("path.home", createTempDir())
.build();
}
@After
public void clearBaseEnvSettings() {
baseEnvSettings = null;
}
public void testIgnoreSystemProperties() {
try {
System.setProperty("es.node.zone", "foo");
Settings settings = settingsBuilder()
.put("node.zone", "bar")
.put(baseEnvSettings)
.build();
Environment env = InternalSettingsPreparer.prepareEnvironment(settings, null);
// Should use setting from the system property
assertThat(env.settings().get("node.zone"), equalTo("foo"));
settings = settingsBuilder()
.put(InternalSettingsPreparer.IGNORE_SYSTEM_PROPERTIES_SETTING, true)
.put("node.zone", "bar")
.put(baseEnvSettings)
.build();
env = InternalSettingsPreparer.prepareEnvironment(settings, null);
// Should use setting from the system property
assertThat(env.settings().get("node.zone"), equalTo("bar"));
} finally {
System.clearProperty("es.node.zone");
}
}
public void testNameSettingsPreference() {
try {
System.setProperty("name", "sys-prop-name");
// Test system property overrides node.name
Settings settings = settingsBuilder()
.put("node.name", "node-name")
.put(baseEnvSettings)
.build();
Environment env = InternalSettingsPreparer.prepareEnvironment(settings, null);
assertThat(env.settings().get("name"), equalTo("sys-prop-name"));
// test name in settings overrides sys prop and node.name
settings = settingsBuilder()
.put("name", "name-in-settings")
.put("node.name", "node-name")
.put(baseEnvSettings)
.build();
env = InternalSettingsPreparer.prepareEnvironment(settings, null);
assertThat(env.settings().get("name"), equalTo("name-in-settings"));
// test only node.name in settings
System.clearProperty("name");
settings = settingsBuilder()
.put("node.name", "node-name")
.put(baseEnvSettings)
.build();
env = InternalSettingsPreparer.prepareEnvironment(settings, null);
assertThat(env.settings().get("name"), equalTo("node-name"));
// test no name at all results in name being set
env = InternalSettingsPreparer.prepareEnvironment(baseEnvSettings, null);
assertThat(env.settings().get("name"), not("name-in-settings"));
assertThat(env.settings().get("name"), not("sys-prop-name"));
assertThat(env.settings().get("name"), not("node-name"));
assertThat(env.settings().get("name"), notNullValue());
} finally {
System.clearProperty("name");
}
}
}

View File

@ -22,6 +22,7 @@ import org.apache.http.impl.client.HttpClients;
import org.apache.lucene.util.LuceneTestCase;
import org.elasticsearch.Version;
import org.elasticsearch.common.Base64;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.cli.CliTool;
import org.elasticsearch.common.cli.CliTool.ExitStatus;
import org.elasticsearch.common.cli.CliToolTestCase.CaptureOutputTerminal;
@ -82,6 +83,7 @@ import static org.jboss.netty.handler.codec.http.HttpVersion.HTTP_1_1;
@LuceneTestCase.SuppressFileSystems("*") // TODO: clean up this test to allow extra files
// TODO: jimfs is really broken here (throws wrong exception from detection method).
// if its in your classpath, then do not use plugins!!!!!!
@SuppressForbidden(reason = "modifies system properties intentionally")
public class PluginManagerTests extends ESIntegTestCase {
private Environment environment;

View File

@ -21,6 +21,7 @@ package org.elasticsearch.plugins;
import org.elasticsearch.Build;
import org.elasticsearch.Version;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.http.client.HttpDownloadHelper;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.env.Environment;
@ -42,6 +43,7 @@ import static org.hamcrest.Matchers.is;
/**
*
*/
@SuppressForbidden(reason = "modifies system properties intentionally")
public class PluginManagerUnitTests extends ESTestCase {
@After
public void cleanSystemProperty() {

View File

@ -22,6 +22,7 @@ package org.elasticsearch.tribe;
import org.elasticsearch.client.Client;
import org.elasticsearch.cluster.ClusterState;
import org.elasticsearch.cluster.node.DiscoveryNode;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.settings.Settings;
import org.elasticsearch.node.Node;
import org.elasticsearch.node.NodeBuilder;
@ -42,6 +43,7 @@ import static org.hamcrest.CoreMatchers.equalTo;
* all the time, while we need to make the tribe node accept them in this case, so that we can verify that they are not read again as part
* of the tribe client nodes initialization. Note that the started nodes will obey to the 'node.mode' settings as the internal cluster does.
*/
@SuppressForbidden(reason = "modifies system properties intentionally")
public class TribeUnitTests extends ESTestCase {
private static Node tribe1;

View File

@ -84,6 +84,9 @@ public class BootstrapForTesting {
// initialize probes
Bootstrap.initializeProbes();
// initialize sysprops
BootstrapInfo.getSystemProperties();
// check for jar hell
try {
JarHell.checkJarHell();

View File

@ -21,6 +21,7 @@ package org.elasticsearch.common.cli;
import org.elasticsearch.ExceptionsHelper;
import org.elasticsearch.common.Strings;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.test.ESTestCase;
import org.elasticsearch.test.StreamsUtils;
import org.junit.After;
@ -40,11 +41,13 @@ import static org.hamcrest.Matchers.hasSize;
public abstract class CliToolTestCase extends ESTestCase {
@Before
@SuppressForbidden(reason = "sets es.default.path.home during tests")
public void setPathHome() {
System.setProperty("es.default.path.home", createTempDir().toString());
}
@After
@SuppressForbidden(reason = "clears es.default.path.home during tests")
public void clearPathHome() {
System.clearProperty("es.default.path.home");
}

View File

@ -42,6 +42,7 @@ import org.elasticsearch.bootstrap.BootstrapForTesting;
import org.elasticsearch.cache.recycler.MockPageCacheRecycler;
import org.elasticsearch.client.Requests;
import org.elasticsearch.cluster.metadata.IndexMetaData;
import org.elasticsearch.common.SuppressForbidden;
import org.elasticsearch.common.io.PathUtils;
import org.elasticsearch.common.io.PathUtilsForTesting;
import org.elasticsearch.common.logging.ESLogger;
@ -163,6 +164,7 @@ public abstract class ESTestCase extends LuceneTestCase {
// randomize and override the number of cpus so tests reproduce regardless of real number of cpus
@BeforeClass
@SuppressForbidden(reason = "sets the number of cpus during tests")
public static void setProcessors() {
int numCpu = TestUtil.nextInt(random(), 1, 4);
System.setProperty(EsExecutors.DEFAULT_SYSPROP, Integer.toString(numCpu));
@ -170,6 +172,7 @@ public abstract class ESTestCase extends LuceneTestCase {
}
@AfterClass
@SuppressForbidden(reason = "clears the number of cpus during tests")
public static void restoreProcessors() {
System.clearProperty(EsExecutors.DEFAULT_SYSPROP);
}