Skip to content

Commit

Permalink
Add tests for Security Manager (#2539)
Browse files Browse the repository at this point in the history
* create container for simple test apps

* refactor ServiceIT + test security manager warn

* reproduce one issue with SecurityManager

* wip : add remote debug + better tmp files

* make agent work better with security manager

* make test pass again

* rename test

* add convenient remote debug for JVM in containers
  • Loading branch information
SylvainJuge committed Mar 6, 2023
1 parent b242cc6 commit a13845d
Show file tree
Hide file tree
Showing 5 changed files with 348 additions and 56 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
*/
package co.elastic.apm.agent.common.util;

import java.security.AccessControlException;
import java.security.AccessController;
import java.security.PrivilegedAction;

Expand Down Expand Up @@ -54,7 +55,21 @@ public static boolean isDisabled() {
}

private static boolean isDisabledThroughConfiguration() {
return System.getProperty(DISABLED_SYSTEM_PROPERTY) != null || System.getenv(DISABLED_ENV_VARIABLE) != null;
if (System.getSecurityManager() == null) {
return System.getProperty(DISABLED_SYSTEM_PROPERTY) != null || System.getenv(DISABLED_ENV_VARIABLE) != null;
} else {
try {
return AccessController.doPrivileged(new PrivilegedAction<Boolean>() {
@Override
public Boolean run() {
return System.getProperty(DISABLED_SYSTEM_PROPERTY) != null || System.getenv(DISABLED_ENV_VARIABLE) != null;
}
});
} catch (AccessControlException ace) {
// we can't use JVM system properties because security manager prevents it, we'd better be able to log something for the end user
return false;
}
}
}

public static void printStackTrace(Throwable throwable) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,20 @@
*/
package co.elastic.apm.test;

import java.util.Arrays;

public class Main {

public static void main(String[] args) {
System.out.println("Hello World!");

// don't terminate the JVM too fast otherwise the container startup will appear to fail
if (Arrays.asList(args).contains("wait")) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
throw new IllegalStateException(e);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
/*
* Licensed to Elasticsearch B.V. under one or more contributor
* license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright
* ownership. Elasticsearch B.V. 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 co.elastic.apm.test;

import co.elastic.apm.agent.test.AgentFileAccessor;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.io.TempDir;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import org.testcontainers.containers.GenericContainer;
import org.testcontainers.containers.output.OutputFrame;
import org.testcontainers.containers.wait.strategy.Wait;
import org.testcontainers.containers.wait.strategy.WaitStrategy;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardOpenOption;
import java.time.Duration;
import java.util.Arrays;

import static org.assertj.core.api.Assertions.assertThat;

class AgentSetupIT {

@ParameterizedTest
@ValueSource(strings = {"openjdk:8", "openjdk:11", "openjdk:17"})
void testServiceNameAndVersionFromManifest(String image) {
try (GenericContainer<TestAppContainer> app = testAppWithJavaAgent(image)) {

app.waitingFor(Wait.forLogMessage(".* Starting Elastic APM .*", 1))
.start();

assertThat(app.getLogs()).contains(" as My Service Name (My Service Version) on ");
}
}

@Test
void testSecurityManagerWarning() {
String expectedMsg = "Security manager without agent grant-all permission";

try (TestAppContainer app = testAppWithJavaAgent("openjdk:17")) {

app.withSecurityManager()
.waitingFor(Wait.forLogMessage(expectedMsg, 1))
// we expect startup to fail fast as JVM should not even properly start
.withStartupTimeout(Duration.ofSeconds(1));

app.start();

assertThat(app.getLogs(OutputFrame.OutputType.STDERR)).contains(expectedMsg);
}

}

@Test
void testSecurityManagerWithPolicy(@TempDir Path temp) throws IOException {
Path tempPolicy = temp.resolve("security.policy");

// use a 'grant all' policy for now
Files.write(tempPolicy, Arrays.asList(
"grant codeBase \"file:///tmp/elastic-apm-agent.jar\" {",
" permission java.security.AllPermission;",
"};"), StandardOpenOption.CREATE
);

try (TestAppContainer app = testAppWithJavaAgent("openjdk:17")) {
app.withSecurityManager(tempPolicy)
.withStartupTimeout(Duration.ofSeconds(10))
.waitingFor(Wait.forLogMessage(".*Hello World!.*", 1))
.start();
}
}

private TestAppContainer testAppWithJavaAgent(String image) {
return new TestAppContainer(image)
.withAppJar(Path.of("target/main-app-test.jar"))
.withArguments("wait") // make test app wait a bit so we can stop it
.withJavaAgent(AgentFileAccessor.getPathToJavaagent())
// automatically enable remote debug
.withRemoteDebug();
}

}

This file was deleted.

0 comments on commit a13845d

Please sign in to comment.