Merge pull request #10965 from rmuir/lockdown4
make testing better mimic reality for securitymanager
This commit is contained in:
commit
d62771ac5d
3
pom.xml
3
pom.xml
|
@ -43,6 +43,7 @@
|
|||
<tests.locale>random</tests.locale>
|
||||
<tests.timezone>random</tests.timezone>
|
||||
<tests.slow>false</tests.slow>
|
||||
<tests.security.manager>true</tests.security.manager>
|
||||
<es.logger.level>ERROR</es.logger.level>
|
||||
<tests.heap.size>512m</tests.heap.size>
|
||||
<tests.heapdump.path>${basedir}/logs/</tests.heapdump.path>
|
||||
|
@ -638,8 +639,6 @@
|
|||
<!-- true if we are running tests from maven (as opposed to IDE, etc).
|
||||
allows us to assert certain things work, like libsigar -->
|
||||
<tests.maven>true</tests.maven>
|
||||
<!-- security manager / test.policy -->
|
||||
<java.security.policy>${basedir}/src/main/resources/org/elasticsearch/bootstrap/security.policy</java.security.policy>
|
||||
</systemProperties>
|
||||
</configuration>
|
||||
</execution>
|
||||
|
|
|
@ -0,0 +1,48 @@
|
|||
/*
|
||||
* 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 java.net.URI;
|
||||
import java.security.Permission;
|
||||
import java.security.PermissionCollection;
|
||||
import java.security.Policy;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.URIParameter;
|
||||
|
||||
/** custom policy for union of static and dynamic permissions */
|
||||
public class ESPolicy extends Policy {
|
||||
|
||||
/** template policy file, the one used in tests */
|
||||
static final String POLICY_RESOURCE = "security.policy";
|
||||
|
||||
final Policy template;
|
||||
final PermissionCollection dynamic;
|
||||
|
||||
public ESPolicy(PermissionCollection dynamic) throws Exception {
|
||||
URI uri = getClass().getResource(POLICY_RESOURCE).toURI();
|
||||
this.template = Policy.getInstance("JavaPolicy", new URIParameter(uri));
|
||||
this.dynamic = dynamic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean implies(ProtectionDomain domain, Permission permission) {
|
||||
return template.implies(domain, permission) || dynamic.implies(permission);
|
||||
}
|
||||
}
|
|
@ -19,18 +19,14 @@
|
|||
|
||||
package org.elasticsearch.bootstrap;
|
||||
|
||||
import org.elasticsearch.common.io.PathUtils;
|
||||
import org.elasticsearch.env.Environment;
|
||||
|
||||
import java.io.*;
|
||||
import java.net.URI;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.security.Permission;
|
||||
import java.security.PermissionCollection;
|
||||
import java.security.Permissions;
|
||||
import java.security.Policy;
|
||||
import java.security.ProtectionDomain;
|
||||
import java.security.URIParameter;
|
||||
|
||||
/**
|
||||
* Initializes securitymanager with necessary permissions.
|
||||
|
@ -38,19 +34,15 @@ import java.security.URIParameter;
|
|||
* We use a template file (the one we test with), and add additional
|
||||
* permissions based on the environment (data paths, etc)
|
||||
*/
|
||||
class Security {
|
||||
|
||||
/** template policy file, the one used in tests */
|
||||
static final String POLICY_RESOURCE = "security.policy";
|
||||
|
||||
public class Security {
|
||||
|
||||
/**
|
||||
* Initializes securitymanager for the environment
|
||||
* Can only happen once!
|
||||
*/
|
||||
static void configure(Environment environment) throws Exception {
|
||||
// enable security policy: union of template and environment-based paths.
|
||||
URI template = Security.class.getResource(POLICY_RESOURCE).toURI();
|
||||
Policy.setPolicy(new ESPolicy(template, createPermissions(environment)));
|
||||
Policy.setPolicy(new ESPolicy(createPermissions(environment)));
|
||||
|
||||
// enable security manager
|
||||
System.setSecurityManager(new SecurityManager());
|
||||
|
@ -64,6 +56,7 @@ class Security {
|
|||
// TODO: improve test infra so we can reduce permissions where read/write
|
||||
// is not really needed...
|
||||
Permissions policy = new Permissions();
|
||||
addPath(policy, PathUtils.get(System.getProperty("java.io.tmpdir")), "read,readlink,write,delete");
|
||||
addPath(policy, environment.homeFile(), "read,readlink,write,delete");
|
||||
addPath(policy, environment.configFile(), "read,readlink,write,delete");
|
||||
addPath(policy, environment.logsFile(), "read,readlink,write,delete");
|
||||
|
@ -79,7 +72,7 @@ class Security {
|
|||
}
|
||||
|
||||
/** Add access to path (and all files underneath it */
|
||||
static void addPath(Permissions policy, Path path, String permissions) throws IOException {
|
||||
public static void addPath(Permissions policy, Path path, String permissions) throws IOException {
|
||||
// paths may not exist yet
|
||||
Files.createDirectories(path);
|
||||
// add each path twice: once for itself, again for files underneath it
|
||||
|
@ -88,7 +81,7 @@ class Security {
|
|||
}
|
||||
|
||||
/** Simple checks that everything is ok */
|
||||
static void selfTest() {
|
||||
public static void selfTest() {
|
||||
// check we can manipulate temporary files
|
||||
try {
|
||||
Files.delete(Files.createTempFile(null, null));
|
||||
|
@ -98,20 +91,4 @@ class Security {
|
|||
throw new SecurityException("Security misconfiguration: cannot access java.io.tmpdir", problem);
|
||||
}
|
||||
}
|
||||
|
||||
/** custom policy for union of static and dynamic permissions */
|
||||
static class ESPolicy extends Policy {
|
||||
final Policy template;
|
||||
final PermissionCollection dynamic;
|
||||
|
||||
ESPolicy(URI template, PermissionCollection dynamic) throws Exception {
|
||||
this.template = Policy.getInstance("JavaPolicy", new URIParameter(template));
|
||||
this.dynamic = dynamic;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean implies(ProtectionDomain domain, Permission permission) {
|
||||
return template.implies(domain, permission) || dynamic.implies(permission);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,15 +21,20 @@
|
|||
// On startup, BootStrap reads environment and adds additional permissions
|
||||
// for configured paths to these.
|
||||
|
||||
//// System code permissions:
|
||||
//// These permissions apply to the JDK itself:
|
||||
|
||||
grant codeBase "file:${{java.ext.dirs}}/*" {
|
||||
permission java.security.AllPermission;
|
||||
};
|
||||
|
||||
//// Everything else:
|
||||
|
||||
grant {
|
||||
|
||||
// system jar resources
|
||||
permission java.io.FilePermission "${java.home}${/}-", "read";
|
||||
|
||||
// temporary files
|
||||
permission java.io.FilePermission "${java.io.tmpdir}", "read,write";
|
||||
permission java.io.FilePermission "${java.io.tmpdir}${/}-", "read,write,delete";
|
||||
|
||||
// paths used for running tests
|
||||
// compiled classes
|
||||
permission java.io.FilePermission "${project.basedir}${/}target${/}classes${/}-", "read";
|
||||
|
|
|
@ -40,7 +40,15 @@ public class SecurityTests extends ElasticsearchTestCase {
|
|||
Settings settings = settingsBuilder.build();
|
||||
|
||||
Environment environment = new Environment(settings);
|
||||
Permissions permissions = Security.createPermissions(environment);
|
||||
Path fakeTmpDir = createTempDir();
|
||||
String realTmpDir = System.getProperty("java.io.tmpdir");
|
||||
Permissions permissions;
|
||||
try {
|
||||
System.setProperty("java.io.tmpdir", fakeTmpDir.toString());
|
||||
permissions = Security.createPermissions(environment);
|
||||
} finally {
|
||||
System.setProperty("java.io.tmpdir", realTmpDir);
|
||||
}
|
||||
|
||||
// the fake es home
|
||||
assertTrue(permissions.implies(new FilePermission(esHome.toString(), "read")));
|
||||
|
@ -48,6 +56,8 @@ public class SecurityTests extends ElasticsearchTestCase {
|
|||
assertFalse(permissions.implies(new FilePermission(path.toString(), "read")));
|
||||
// some other sibling
|
||||
assertFalse(permissions.implies(new FilePermission(path.resolve("other").toString(), "read")));
|
||||
// double check we overwrote java.io.tmpdir correctly for the test
|
||||
assertFalse(permissions.implies(new FilePermission(realTmpDir.toString(), "read")));
|
||||
}
|
||||
|
||||
/** test generated permissions for all configured paths */
|
||||
|
@ -63,7 +73,15 @@ public class SecurityTests extends ElasticsearchTestCase {
|
|||
Settings settings = settingsBuilder.build();
|
||||
|
||||
Environment environment = new Environment(settings);
|
||||
Permissions permissions = Security.createPermissions(environment);
|
||||
Path fakeTmpDir = createTempDir();
|
||||
String realTmpDir = System.getProperty("java.io.tmpdir");
|
||||
Permissions permissions;
|
||||
try {
|
||||
System.setProperty("java.io.tmpdir", fakeTmpDir.toString());
|
||||
permissions = Security.createPermissions(environment);
|
||||
} finally {
|
||||
System.setProperty("java.io.tmpdir", realTmpDir);
|
||||
}
|
||||
|
||||
// check that all directories got permissions:
|
||||
// homefile: this is needed unless we break out rules for "lib" dir.
|
||||
|
@ -83,5 +101,9 @@ public class SecurityTests extends ElasticsearchTestCase {
|
|||
}
|
||||
// logs: r/w
|
||||
assertTrue(permissions.implies(new FilePermission(environment.logsFile().toString(), "read,readlink,write,delete")));
|
||||
// temp dir: r/w
|
||||
assertTrue(permissions.implies(new FilePermission(fakeTmpDir.toString(), "read,readlink,write,delete")));
|
||||
// double check we overwrote java.io.tmpdir correctly for the test
|
||||
assertFalse(permissions.implies(new FilePermission(realTmpDir.toString(), "read")));
|
||||
}
|
||||
}
|
||||
|
|
|
@ -93,7 +93,7 @@ import static com.google.common.collect.Lists.newArrayList;
|
|||
public abstract class ElasticsearchTestCase extends LuceneTestCase {
|
||||
|
||||
static {
|
||||
SecurityHack.ensureInitialized();
|
||||
SecurityBootstrap.ensureInitialized();
|
||||
}
|
||||
|
||||
protected final ESLogger logger = Loggers.getLogger(getClass());
|
||||
|
|
|
@ -43,7 +43,7 @@ import org.elasticsearch.test.junit.listeners.ReproduceInfoPrinter;
|
|||
public abstract class ElasticsearchTokenStreamTestCase extends BaseTokenStreamTestCase {
|
||||
|
||||
static {
|
||||
SecurityHack.ensureInitialized();
|
||||
SecurityBootstrap.ensureInitialized();
|
||||
}
|
||||
|
||||
public static Version randomVersion() {
|
||||
|
|
|
@ -21,6 +21,12 @@ package org.elasticsearch.test;
|
|||
|
||||
import org.apache.lucene.util.TestSecurityManager;
|
||||
import org.elasticsearch.bootstrap.Bootstrap;
|
||||
import org.elasticsearch.bootstrap.ESPolicy;
|
||||
import org.elasticsearch.bootstrap.Security;
|
||||
import org.elasticsearch.common.io.PathUtils;
|
||||
|
||||
import java.security.Permissions;
|
||||
import java.security.Policy;
|
||||
|
||||
import static com.carrotsearch.randomizedtesting.RandomizedTest.systemPropertyAsBoolean;
|
||||
|
||||
|
@ -28,18 +34,29 @@ import static com.carrotsearch.randomizedtesting.RandomizedTest.systemPropertyAs
|
|||
* Installs test security manager (ensures it happens regardless of which
|
||||
* test case happens to be first, test ordering, etc).
|
||||
* <p>
|
||||
* Note that this is BS, this should be done by the jvm (by passing -Djava.security.manager).
|
||||
* turning it on/off needs to be the role of maven, not this stuff.
|
||||
* The idea is to mimic as much as possible what happens with ES in production
|
||||
* mode (e.g. assign permissions and install security manager the same way)
|
||||
*/
|
||||
class SecurityHack {
|
||||
class SecurityBootstrap {
|
||||
|
||||
// TODO: can we share more code with the non-test side here
|
||||
// without making things complex???
|
||||
|
||||
static {
|
||||
// just like bootstrap, initialize natives, then SM
|
||||
Bootstrap.initializeNatives(true, true);
|
||||
// for IDEs, we check that security.policy is set
|
||||
if (systemPropertyAsBoolean("tests.security.manager", true) &&
|
||||
System.getProperty("java.security.policy") != null) {
|
||||
System.setSecurityManager(new TestSecurityManager());
|
||||
// install security manager if requested
|
||||
if (systemPropertyAsBoolean("tests.security.manager", false)) {
|
||||
try {
|
||||
// initialize tmpdir the same exact way as bootstrap.
|
||||
Permissions perms = new Permissions();
|
||||
Security.addPath(perms, PathUtils.get(System.getProperty("java.io.tmpdir")), "read,readlink,write,delete");
|
||||
Policy.setPolicy(new ESPolicy(perms));
|
||||
System.setSecurityManager(new TestSecurityManager());
|
||||
Security.selfTest();
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("unable to install test security manager", e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue