Skip to content

Commit

Permalink
Remove SecurityManager references from logging package #16 (#117)
Browse files Browse the repository at this point in the history
Signed-off-by: jmehrens <jason_mehrens@hotmail.com>
  • Loading branch information
jmehrens authored Jan 23, 2024
1 parent 4b7360d commit d223d1f
Show file tree
Hide file tree
Showing 8 changed files with 315 additions and 931 deletions.
16 changes: 4 additions & 12 deletions demos/logging/src/main/java/example/app/FileErrorManager.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2009, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2023 Jason Mehrens. All Rights Reserved.
* Copyright (c) 2009, 2024 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2024 Jason Mehrens. All Rights Reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
Expand All @@ -18,8 +18,6 @@
import java.io.OutputStream;
import java.io.PrintStream;
import java.lang.reflect.Constructor;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.logging.ErrorManager;
import java.util.logging.Level;
import java.util.logging.LogManager;
Expand Down Expand Up @@ -269,13 +267,7 @@ private File getEmailStore() {
String dir = manager.getProperty(
getClass().getName().concat(".pattern"));
if (dir == null) {
dir = AccessController.doPrivileged(new PrivilegedAction<String>() {

@Override
public String run() {
return System.getProperty("java.io.tmpdir", ".");
}
});
dir = System.getProperty("java.io.tmpdir", ".");
}
return new File(dir);
}
Expand All @@ -291,7 +283,7 @@ private OutputStream wrap(OutputStream out) {
assert out != null;
Class<?> k;
try {
k = Class.forName("example.app.NewlineOutputStream");
k = Class.forName("example.app.internal.NewlineOutputStream");
if (OutputStream.class.isAssignableFrom(k)) {
Constructor<?> c = k.getConstructor(OutputStream.class);
return (OutputStream) c.newInstance(out);
Expand Down
19 changes: 2 additions & 17 deletions demos/logging/src/main/java/example/app/MailHandlerDemo.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
/*
* Copyright (c) 2009, 2023 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2023 Jason Mehrens. All Rights Reserved.
* Copyright (c) 2009, 2024 Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2009, 2024 Jason Mehrens. All Rights Reserved.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Distribution License v. 1.0, which is available at
Expand Down Expand Up @@ -151,21 +151,6 @@ private static void checkConfig(String prefix, PrintStream err) {
err.println(prefix + ": LOGGER=" + LOGGER.getLevel());
err.println(prefix + ": JVM id "
+ ManagementFactory.getRuntimeMXBean().getName());
err.println(prefix + ": java.security.debug="
+ System.getProperty("java.security.debug"));
SecurityManager sm = System.getSecurityManager();
if (sm != null) {
err.println(prefix + ": SecurityManager.class="
+ sm.getClass().getName());
err.println(prefix + ": SecurityManager classLoader="
+ toString(sm.getClass().getClassLoader()));
err.println(prefix + ": SecurityManager.toString=" + sm);
} else {
err.println(prefix + ": SecurityManager.class=null");
err.println(prefix + ": SecurityManager.toString=null");
err.println(prefix + ": SecurityManager classLoader=null");
}

String policy = System.getProperty("java.security.policy");
if (policy != null) {
File f = new File(policy);
Expand Down
1 change: 1 addition & 0 deletions doc/src/main/resources/docs/CHANGES.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ for the Eclipse EE4J Angus Mail project:
----------------------------
The following bugs have been fixed in the 2.0.3 release.

16: Remove SecurityManager references from logging package
52: CompactFormatter support for LogRecord::getLongThreadID
107: java.io.UnsupportedEncodingException: en_US.iso885915 if charset is "en_US.iso885915"
110: WildFly support for MailHandler
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.lang.reflect.UndeclaredThrowableException;
import java.security.AccessController;
import java.security.PrivilegedAction;
import java.util.Collections;
import java.util.Comparator;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Locale;
import java.util.Objects;
import java.util.Properties;
import java.util.logging.ErrorManager;
import java.util.logging.Filter;
Expand All @@ -40,7 +40,6 @@
import java.util.logging.LogManager;
import java.util.logging.LogRecord;
import java.util.logging.Logger;
import java.util.logging.LoggingPermission;

/**
* An adapter class to allow the Mail API to access the LogManager properties.
Expand Down Expand Up @@ -171,7 +170,7 @@ private static Object loadLogManager() {
try {
m = LogManager.getLogManager();
} catch (final LinkageError | RuntimeException restricted) {
m = readConfiguration();
m = readConfiguration(); //GAE will forbid access to LogManager
}
return m;
}
Expand All @@ -197,11 +196,8 @@ private static Properties readConfiguration() {
String n = System.getProperty("java.util.logging.config.file");
if (n != null) {
final File f = new File(n).getCanonicalFile();
final InputStream in = new FileInputStream(f);
try {
try (InputStream in = new FileInputStream(f)) {
props.load(in);
} finally {
in.close();
}
}
} catch (final LinkageError | Exception permissionsOrMalformed) {
Expand All @@ -219,10 +215,7 @@ private static Properties readConfiguration() {
* @since JavaMail 1.5.3
*/
static String fromLogManager(final String name) {
if (name == null) {
throw new NullPointerException();
}

Objects.requireNonNull(name);
final Object m = LOG_MANAGER;
try {
if (m instanceof Properties) {
Expand All @@ -237,7 +230,7 @@ static String fromLogManager(final String name) {
return ((LogManager) m).getProperty(name);
}
} catch (final LinkageError | RuntimeException restricted) {
}
} //GAE will forbid access to LogManager
}
return null;
}
Expand All @@ -256,55 +249,46 @@ static void checkLogManagerAccess() {
if (m != null) {
try {
if (m instanceof LogManager) {
checked = true;
((LogManager) m).checkAccess();
try {
LogManager.class.getMethod("checkAccess").invoke(m);
checked = true;
} catch (InvocationTargetException ite) {
Throwable cause = ite.getCause();
if (cause instanceof SecurityException) {
checked = true;
throw (SecurityException) cause;
}

if (cause instanceof UnsupportedOperationException) {
checked = true;
}
} catch (NoSuchMethodException removed) {
checked = true;
} catch (ReflectiveOperationException fallthrough) {
}
}
} catch (final SecurityException notAllowed) {
if (checked) {
throw notAllowed;
}
} catch (final LinkageError | RuntimeException restricted) {
}
}

if (!checked) {
checkLoggingAccess();
} //GAE will forbid access to LogManager
}
}

/**
* Check that the current context is trusted to modify the logging
* configuration when the LogManager is not present. This requires
* LoggingPermission("control").
*
* @throws SecurityException if a security manager exists and the caller
* does not have {@code LoggingPermission("control")}.
* @since JavaMail 1.5.3
*/
private static void checkLoggingAccess() {
/**
* Some environments selectively enforce logging permissions by allowing
* access to loggers but not allowing access to handlers. This is an
* indirect way of checking for LoggingPermission when the LogManager is
* not present. The root logger will lazy create handlers so the global
* logger is used instead as it is a known named logger with well
* defined behavior. If the global logger is a subclass then fallback to
* using the SecurityManager.
* defined behavior. Contractually, Logger::remove will check
* permission before checking if the argument is null.
* See JDK-8023168
*/
boolean checked = false;
final Logger global = Logger.getLogger("global");
try {
if (Logger.class == global.getClass()) {
global.removeHandler((Handler) null);
checked = true;
}
} catch (final NullPointerException unexpected) {
}

if (!checked) {
final SecurityManager sm = System.getSecurityManager();
if (sm != null) {
sm.checkPermission(new LoggingPermission("control", null));
try {
Logger.getGlobal().removeHandler((Handler) null);
} catch (final NullPointerException unexpected) {
}
}
}
Expand Down Expand Up @@ -332,9 +316,7 @@ static boolean hasLogManager() {
*/
@SuppressWarnings("UseSpecificCatch")
static Comparable<?> getZonedDateTime(LogRecord record) {
if (record == null) {
throw new NullPointerException();
}
Objects.requireNonNull(record);
final Method m = ZDT_OF_INSTANT;
if (m != null) {
try {
Expand Down Expand Up @@ -368,10 +350,7 @@ static Comparable<?> getZonedDateTime(LogRecord record) {
* @since Angus Mail 2.0.3
*/
static Long getLongThreadID(final LogRecord record) {
if (record == null) {
throw new NullPointerException();
}

Objects.requireNonNull(record);
final Method m = LR_GET_LONG_TID;
if (m != null) {
try {
Expand Down Expand Up @@ -409,6 +388,7 @@ static Long getLongThreadID(final LogRecord record) {
* @since JavaMail 1.5.3
*/
static String getLocalHost(final Object s) throws Exception {
Objects.requireNonNull(s);
try {
final Method m = s.getClass().getMethod("getLocalHost");
if (!Modifier.isStatic(m.getModifiers())
Expand Down Expand Up @@ -443,10 +423,7 @@ static String getLocalHost(final Object s) throws Exception {
* @since JavaMail 1.5.5
*/
static long parseDurationToMillis(final CharSequence value) throws Exception {
if (value == null) {
throw new NullPointerException();
}

Objects.requireNonNull(value);
try {
final Class<?> k = findClass("java.time.Duration");
final Method parse = k.getMethod("parse", CharSequence.class);
Expand Down Expand Up @@ -586,10 +563,7 @@ static Comparator<? super LogRecord> newComparator(String name) throws Exception
*/
@SuppressWarnings({"unchecked", "ThrowableResultIgnored"})
static <T> Comparator<T> reverseOrder(final Comparator<T> c) {
if (c == null) {
throw new NullPointerException();
}

Objects.requireNonNull(c);
Comparator<T> reverse = null;
//Comparator in JDK8 has 'reversed' as a default method.
//This code calls that method first to allow custom
Expand Down Expand Up @@ -794,18 +768,12 @@ static <T> T newObjectFrom(String name, Class<T> type) throws Exception {
* @param ite any invocation target.
* @return the exception.
* @throws VirtualMachineError if present as cause.
* @throws ThreadDeath if present as cause.
* @since JavaMail 1.4.5
*/
private static Exception paramOrError(InvocationTargetException ite) {
final Throwable cause = ite.getCause();
if (cause != null) {
//Bitwise inclusive OR produces tighter bytecode for instanceof
//and matches with multicatch syntax.
if (cause instanceof VirtualMachineError
| cause instanceof ThreadDeath) {
throw (Error) cause;
}
if (cause instanceof VirtualMachineError) {
throw (Error) cause;
}
return ite;
}
Expand Down Expand Up @@ -881,7 +849,7 @@ private static Class<?> tryLoad(String name, ClassLoader l) throws ClassNotFound
* @return any array of class loaders. Indexes may be null.
*/
private static ClassLoader[] getClassLoaders() {
return AccessController.doPrivileged(new PrivilegedAction<ClassLoader[]>() {
return runOrDoPrivileged(new PrivilegedAction<ClassLoader[]>() {

@SuppressWarnings("override") //JDK-6954234
public ClassLoader[] run() {
Expand All @@ -902,6 +870,58 @@ public ClassLoader[] run() {
});
}

/**
* Executes a PrivilegedAction without permissions then falling back to
* running with elevated permissions.
*
* Any unchecked exceptions from the action are passed through this API.
*
* @param <T> the action return type.
* @param a the PrivilegedAction object.
* @return the result.
* @throws NullPointerException if the given action is null.
* @throws UndeclaredThrowableException if a checked exception is thrown.
* @since Angus Mail 2.0.3
*/
static <T> T runOrDoPrivileged(final PrivilegedAction<T> a) {
Objects.requireNonNull(a);
try {
return a.run();
} catch (SecurityException sandbox) {
return invokeAccessController(a);
}
}

/**
* Reflective call to access controller for sandbox environments.
* Any unchecked exceptions from the action are passed through this API.
*
* @param <T> the return type of the action.
* @param a a non-null action.
* @return the result.
* @throws UnsupportedOperationException if not allowed.
* @throws UndeclaredThrowableException if a checked exception is thrown.
* @since Angus Mail 2.0.3
*/
@SuppressWarnings("unchecked")
private static <T> T invokeAccessController(final PrivilegedAction<T> a) {
assert a != null;
try {
Class<?> c = Class.forName("java.security.AccessController");
return (T) c.getMethod("doPrivileged", PrivilegedAction.class)
.invoke((Object) null, a);
} catch (ReflectiveOperationException roe) {
Throwable cause = roe.getCause();
if (cause instanceof RuntimeException) {
throw (RuntimeException) cause;
} else if (cause instanceof Error) {
throw (Error) cause;
} else {
throw new UndeclaredThrowableException(roe);
}
}
}

/**
* The namespace prefix to search LogManager and defaults.
*/
Expand Down
Loading

0 comments on commit d223d1f

Please sign in to comment.