Skip to content
This repository has been archived by the owner on Sep 2, 2022. It is now read-only.

Commit

Permalink
Browse files Browse the repository at this point in the history
8268349: Provide clear run-time warnings about Security Manager depre…
…cation

Reviewed-by: lancea, mullan, alanb
  • Loading branch information
wangweij committed Jun 22, 2021
1 parent 4099810 commit ef4ba22
Show file tree
Hide file tree
Showing 6 changed files with 144 additions and 75 deletions.
46 changes: 37 additions & 9 deletions src/java.base/share/classes/java/lang/System.java
Expand Up @@ -44,14 +44,16 @@
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;
Expand Down Expand Up @@ -324,6 +326,16 @@ private static void checkIO() {
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.
*
Expand Down Expand Up @@ -362,16 +374,29 @@ private static void checkIO() {
* 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");
}
}
}
Expand Down Expand Up @@ -2191,10 +2216,13 @@ private static void initPhase3() {
}

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);

Expand Down
Expand Up @@ -36,6 +36,7 @@
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;
Expand All @@ -44,15 +45,11 @@
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
Expand Down Expand Up @@ -202,6 +199,10 @@ static void setSecurityManager() {
}
}

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;
Expand Down Expand Up @@ -235,12 +236,7 @@ static LoggerFinder getLoggerFinder(Class<?> expectedClass,
}
} 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());
Expand Down
132 changes: 89 additions & 43 deletions test/jdk/java/lang/System/SecurityManagerWarnings.java
Expand Up @@ -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);
}
}
9 changes: 3 additions & 6 deletions test/jdk/java/lang/invoke/lambda/LogGeneratedClassesTest.java
Expand Up @@ -147,9 +147,8 @@ public void testDumpDirNotExist() throws IOException {
"-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");
Expand All @@ -164,9 +163,8 @@ public void testDumpDirIsFile() throws IOException {
"-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");
Expand Down Expand Up @@ -224,9 +222,8 @@ public void testDumpDirNotWritable() throws IOException {
"-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");
Expand Down
10 changes: 7 additions & 3 deletions test/jdk/java/net/spi/URLStreamHandlerProvider/Basic.java
Expand Up @@ -86,10 +86,14 @@ public static void main(String[] args) throws Throwable {
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 ||
Expand Down
6 changes: 2 additions & 4 deletions test/jdk/java/security/ProtectionDomain/RecursionDebug.java
@@ -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
Expand All @@ -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
Expand Down Expand Up @@ -87,7 +87,5 @@ public static void main(String[] args) throws Exception {
throw new Exception
("Test with custom non-bootclass SecurityManager failed");
}

System.setSecurityManager(null);
}
}

1 comment on commit ef4ba22

@openjdk-notifier
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.