8268349: Provide clear run-time warnings about Security Manager deprecation

Reviewed-by: lancea, mullan, alanb
This commit is contained in:
Weijun Wang 2021-06-22 02:06:59 +00:00
parent 4099810b29
commit ef4ba224c4
6 changed files with 144 additions and 75 deletions
src/java.base/share/classes/java/lang
test/jdk/java
lang
System
LoggerFinder/internal/LoggerFinderLoaderTest
SecurityManagerWarnings.java
invoke/lambda
net/spi/URLStreamHandlerProvider
security/ProtectionDomain

@ -44,14 +44,16 @@ import java.lang.reflect.Executable;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.net.URI;
import java.net.URL;
import java.nio.charset.CharacterCodingException;
import java.security.AccessControlContext;
import java.security.ProtectionDomain;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.nio.channels.Channel;
import java.nio.channels.spi.SelectorProvider;
import java.nio.charset.Charset;
import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.CodeSource;
import java.security.PrivilegedAction;
import java.security.ProtectionDomain;
import java.util.List;
import java.util.Map;
import java.util.Objects;
@ -324,6 +326,16 @@ public final class System {
private static native void setOut0(PrintStream out);
private static native void setErr0(PrintStream err);
// Remember initial System.err. setSecurityManager() warning goes here
private static volatile @Stable PrintStream initialErrStream;
private static URL codeSource(Class<?> clazz) {
PrivilegedAction<ProtectionDomain> pa = clazz::getProtectionDomain;
@SuppressWarnings("removal")
CodeSource cs = AccessController.doPrivileged(pa).getCodeSource();
return (cs != null) ? cs.getLocation() : null;
}
/**
* Sets the system-wide security manager.
*
@ -362,16 +374,29 @@ public final class System {
* method.
*/
@Deprecated(since="17", forRemoval=true)
@CallerSensitive
public static void setSecurityManager(@SuppressWarnings("removal") SecurityManager sm) {
if (allowSecurityManager()) {
System.err.println("WARNING: java.lang.System::setSecurityManager" +
" is deprecated and will be removed in a future release.");
var callerClass = Reflection.getCallerClass();
URL url = codeSource(callerClass);
final String source;
if (url == null) {
source = callerClass.getName();
} else {
source = callerClass.getName() + " (" + url + ")";
}
initialErrStream.printf("""
WARNING: A terminally deprecated method in java.lang.System has been called
WARNING: System::setSecurityManager has been called by %s
WARNING: Please consider reporting this to the maintainers of %s
WARNING: System::setSecurityManager will be removed in a future release
""", source, callerClass.getName());
implSetSecurityManager(sm);
} else {
// security manager not allowed
if (sm != null) {
throw new UnsupportedOperationException(
"Runtime configured to disallow security manager");
"The Security Manager is deprecated and will be removed in a future release");
}
}
}
@ -2191,10 +2216,13 @@ public final class System {
}
if (needWarning) {
System.err.println("WARNING: The Security Manager is deprecated" +
" and will be removed in a future release.");
System.err.println("""
WARNING: A command line option has enabled the Security Manager
WARNING: The Security Manager is deprecated and will be removed in a future release""");
}
initialErrStream = System.err;
// initializing the system class loader
VM.initLevel(3);

@ -36,6 +36,7 @@ import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.ResourceBundle;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicBoolean;
@ -44,15 +45,11 @@ import java.util.function.Supplier;
import java.lang.System.LoggerFinder;
import java.lang.System.Logger;
import java.lang.System.Logger.Level;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.EnumSet;
import java.util.Iterator;
import java.util.Locale;
import java.util.ServiceConfigurationError;
import java.util.ServiceLoader;
import java.util.concurrent.atomic.AtomicReference;
import jdk.internal.logger.SimpleConsoleLogger;
/**
* @test
@ -202,6 +199,10 @@ public class LoggerFinderLoaderTest {
}
}
private static String withoutWarning(String in) {
return in.lines().filter(s -> !s.startsWith("WARNING:")).collect(Collectors.joining());
}
static LoggerFinder getLoggerFinder(Class<?> expectedClass,
String errorPolicy, boolean singleton) {
LoggerFinder provider = null;
@ -235,12 +236,7 @@ public class LoggerFinderLoaderTest {
}
} else if ("QUIET".equals(errorPolicy.toUpperCase(Locale.ROOT))) {
String warning = ErrorStream.errorStream.peek();
String smDeprecationWarning
= "WARNING: java.lang.System::setSecurityManager is deprecated and will be removed in a future release."
+ System.getProperty("line.separator");
if (warning.startsWith(smDeprecationWarning)) {
warning = warning.substring(smDeprecationWarning.length());
}
warning = withoutWarning(warning);
if (!warning.isEmpty()) {
throw new RuntimeException("Unexpected error message found: "
+ ErrorStream.errorStream.peek());

@ -23,70 +23,116 @@
/*
* @test
* @bug 8266459
* @bug 8266459 8268349
* @summary check various warnings
* @library /test/lib
*/
import jdk.test.lib.JDKToolFinder;
import jdk.test.lib.process.OutputAnalyzer;
import jdk.test.lib.process.ProcessTools;
import jdk.test.lib.util.JarUtils;
import java.security.Permission;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.PrintStream;
import java.nio.file.Files;
import java.nio.file.Path;
public class SecurityManagerWarnings {
public static void main(String args[]) throws Exception {
if (args.length == 0) {
run(null)
.shouldHaveExitValue(0)
.shouldContain("SM is enabled: false")
.shouldNotContain("Security Manager is deprecated")
.shouldContain("setSecurityManager is deprecated");
run("allow")
.shouldHaveExitValue(0)
.shouldContain("SM is enabled: false")
.shouldNotContain("Security Manager is deprecated")
.shouldContain("setSecurityManager is deprecated");
run("disallow")
.shouldNotHaveExitValue(0)
.shouldContain("SM is enabled: false")
.shouldNotContain("Security Manager is deprecated")
.shouldContain("UnsupportedOperationException");
run("SecurityManagerWarnings$MySM")
.shouldHaveExitValue(0)
.shouldContain("SM is enabled: true")
.shouldContain("Security Manager is deprecated")
.shouldContain("setSecurityManager is deprecated");
run("")
.shouldNotHaveExitValue(0)
.shouldContain("SM is enabled: true")
.shouldContain("Security Manager is deprecated")
.shouldContain("AccessControlException");
run("default")
.shouldNotHaveExitValue(0)
.shouldContain("SM is enabled: true")
.shouldContain("Security Manager is deprecated")
.shouldContain("AccessControlException");
Files.writeString(Path.of("policy"), """
grant {
permission java.lang.RuntimePermission "setIO";
permission java.lang.RuntimePermission "createSecurityManager";
permission java.lang.RuntimePermission "setSecurityManager";
};
""");
String testClasses = System.getProperty("test.classes");
allowTest(null, testClasses);
allowTest("allow", testClasses);
disallowTest("disallow", testClasses);
enableTest("", testClasses);
enableTest("default", testClasses);
enableTest("java.lang.SecurityManager", testClasses);
JarUtils.createJarFile(Path.of("a.jar"),
Path.of(testClasses),
Path.of("SecurityManagerWarnings.class"));
allowTest(null, "a.jar");
} else {
System.out.println("SM is enabled: " + (System.getSecurityManager() != null));
System.setSecurityManager(new SecurityManager());
PrintStream oldErr = System.err;
// Modify System.err, thus make sure warnings are always printed
// to the original System.err and will not be swallowed.
System.setErr(new PrintStream(new ByteArrayOutputStream()));
try {
System.setSecurityManager(new SecurityManager());
} catch (Exception e) {
// Exception messages must show in original stderr
e.printStackTrace(oldErr);
throw e;
}
}
}
static OutputAnalyzer run(String prop) throws Exception {
// When SM is allowed, no startup warning, has setSM warning
static void allowTest(String prop, String cp) throws Exception {
checkInstallMessage(run(prop, cp), cp)
.shouldHaveExitValue(0)
.stdoutShouldContain("SM is enabled: false")
.shouldNotContain("A command line option");
}
// When SM is disallowed, no startup warning, setSM fails
static void disallowTest(String prop, String cp) throws Exception {
run(prop, cp)
.shouldNotHaveExitValue(0)
.stdoutShouldContain("SM is enabled: false")
.shouldNotContain("A command line option")
.shouldNotContain("A terminally deprecated method")
.stderrShouldContain("UnsupportedOperationException: The Security Manager is deprecated and will be removed in a future release");
}
// When SM is allowed, has startup warning, has setSM warning
static void enableTest(String prop, String cp) throws Exception {
checkInstallMessage(run(prop, cp), cp)
.shouldHaveExitValue(0)
.stdoutShouldContain("SM is enabled: true")
.stderrShouldContain("WARNING: A command line option has enabled the Security Manager")
.stderrShouldContain("WARNING: The Security Manager is deprecated and will be removed in a future release");
}
// Check the setSM warning
static OutputAnalyzer checkInstallMessage(OutputAnalyzer oa, String cp) {
String uri = new File(cp).toURI().toString();
return oa
.stderrShouldContain("WARNING: A terminally deprecated method in java.lang.System has been called")
.stderrShouldContain("WARNING: System::setSecurityManager has been called by SecurityManagerWarnings (" + uri + ")")
.stderrShouldContain("WARNING: Please consider reporting this to the maintainers of SecurityManagerWarnings")
.stderrShouldContain("WARNING: System::setSecurityManager will be removed in a future release");
}
static OutputAnalyzer run(String prop, String cp) throws Exception {
ProcessBuilder pb;
if (prop == null) {
return ProcessTools.executeTestJvm(
pb = new ProcessBuilder(
JDKToolFinder.getJDKTool("java"),
"-cp", cp,
"SecurityManagerWarnings", "run");
} else {
return ProcessTools.executeTestJvm(
pb = new ProcessBuilder(
JDKToolFinder.getJDKTool("java"),
"-cp", cp,
"-Djava.security.manager=" + prop,
"-Djava.security.policy=policy",
"SecurityManagerWarnings", "run");
}
}
// This SecurityManager allows everything!
public static class MySM extends SecurityManager {
@Override
public void checkPermission(Permission perm) {
}
return ProcessTools.executeProcess(pb);
}
}

@ -147,9 +147,8 @@ public class LogGeneratedClassesTest extends LUtils {
"-Djdk.internal.lambda.dumpProxyClasses=notExist",
"com.example.TestLambda");
assertEquals(tr.testOutput.stream()
.filter(s -> !s.contains("setSecurityManager is deprecated"))
.filter(s -> s.startsWith("WARNING"))
.peek(s -> assertTrue(s.contains("does not exist")))
.filter(s -> s.contains("does not exist"))
.count(),
1, "only show error once");
tr.assertZero("Should still return 0");
@ -164,9 +163,8 @@ public class LogGeneratedClassesTest extends LUtils {
"-Djdk.internal.lambda.dumpProxyClasses=file",
"com.example.TestLambda");
assertEquals(tr.testOutput.stream()
.filter(s -> !s.contains("setSecurityManager is deprecated"))
.filter(s -> s.startsWith("WARNING"))
.peek(s -> assertTrue(s.contains("not a directory")))
.filter(s -> s.contains("not a directory"))
.count(),
1, "only show error once");
tr.assertZero("Should still return 0");
@ -224,9 +222,8 @@ public class LogGeneratedClassesTest extends LUtils {
"-Djdk.internal.lambda.dumpProxyClasses=readOnly",
"com.example.TestLambda");
assertEquals(tr.testOutput.stream()
.filter(s -> !s.contains("setSecurityManager is deprecated"))
.filter(s -> s.startsWith("WARNING"))
.peek(s -> assertTrue(s.contains("not writable")))
.filter(s -> s.contains("not writable"))
.count(),
1, "only show error once");
tr.assertZero("Should still return 0");

@ -86,10 +86,14 @@ public class Basic {
static final String SECURITY_MANAGER_DEPRECATED
= "WARNING: The Security Manager is deprecated and will be removed in a future release."
+ System.getProperty("line.separator");
private static String withoutWarning(String in) {
return in.lines().filter(s -> !s.startsWith("WARNING:")).collect(Collectors.joining());
}
static final Consumer<Result> KNOWN = r -> {
if (r.exitValue != 0 ||
(!r.output.isEmpty() && !r.output.equals(SECURITY_MANAGER_DEPRECATED)))
throw new RuntimeException(r.output);
if (r.exitValue != 0 || !withoutWarning(r.output).isEmpty())
throw new RuntimeException("[" + r.output + "]");
};
static final Consumer<Result> UNKNOWN = r -> {
if (r.exitValue == 0 ||

@ -1,5 +1,5 @@
/*
* Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2003, 2021, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -23,7 +23,7 @@
/*
* @test
* @bug 4947618
* @bug 4947618 8268349
* @summary Recursion problem in security manager and policy code
*
* @run main/othervm/policy=Recursion.policy -Djava.security.debug=domain RecursionDebug
@ -87,7 +87,5 @@ public class RecursionDebug {
throw new Exception
("Test with custom non-bootclass SecurityManager failed");
}
System.setSecurityManager(null);
}
}