Version
thymeleaf 3.0.15
Phenomenon
An error is reported when getting the exception message through ${session.SPRING_SECURITY_LAST_EXCEPTION.getMessage()} in the thymeleaf template
Caused by: org.springframework.expression.EvaluationException: Calling methods is forbidden for type ‘java.lang.RuntimeException’ in Thymeleaf expressions. Blacklisted classes are: [java.util.concurrent.RunnableFuture, java.util.concurrent.Executor, java.lang.Runtime, java.util.concurrent.FutureTask, java.util.concurrent.ListenableFuture, java.lang.Runnable, java.util.concurrent.Future, java.lang.Thread, java.lang.reflect.Executable, java.lang.Class, java.lang.ClassLoader, java.sql.DriverManager].
reason
In thymeleaf 3.0.15, classes prefixed with java.lang.Runtime are blacklisted and not allowed to be accessed in templates
solve
Exceptions should be thrown as Exception instead of RuntimeException, other similar problems can be solved
source code
- package thymeleaf-spring5-3.0.15
org.thymeleaf.spring5.expression.ThymeleafEvaluationContext
static final class ThymeleafEvaluationContextACLMethodResolver extends ReflectiveMethodResolver {
ThymeleafEvaluationContextACLMethodResolver() {
super();
}
@Override
public MethodExecutor resolve(
final EvaluationContext context, final Object targetObject,
final String name, final List<TypeDescriptor> argumentTypes) throws AccessException {
final Class<?> type = (targetObject instanceof Class ? (Class<?>) targetObject : targetObject.getClass());
// 判断对象是否时允许访问的类型
if (!ExpressionUtils.isTypeAllowed(type.getName())) {
// We will only specifically allow calling "Object.getClass()" and "Class.getName()"
if (!(Class.class.equals(type) && "getName".equals(name))
&& !(Object.class.equals(type) && "getClass".equals(name))) {
throw new EvaluationException(
String.format(
"Calling methods is forbidden for type '%s' in Thymeleaf expressions. " +
"Blacklisted classes are: %s.",
type.getName(), ExpressionUtils.getBlacklist()));
}
}
return super.resolve(context, targetObject, name, argumentTypes);
}
}
- 包thymeleaf-3.0.15
org.thymeleaf.util. ExpressionUtils
public final class ExpressionUtils {
// 所有黑名单类名前缀
private static final Set<String> BLOCKED_CLASS_NAME_PREFIXES =
new HashSet<String>(Arrays.asList(
"java.lang.Runtime", "java.lang.Thread", "java.lang.Class", "java.lang.ClassLoader",
"java.lang.Runnable", "java.lang.reflect.Executable",
"java.util.concurrent.Future", "java.util.concurrent.FutureTask",
"java.util.concurrent.RunnableFuture", "java.util.concurrent.ListenableFuture",
"java.util.concurrent.Executor",
"java.sql.DriverManager"));
public static boolean isTypeAllowed(final String typeName) {
Validate.notNull(typeName, "Type name cannot be null");
final int i0 = typeName.indexOf('.');
if (i0 >= 0) {
final String package0 = typeName.substring(0, i0);
if ("java".equals(package0)) {
// This is the only prefix that might be blocked
for (final String prefix : BLOCKED_CLASS_NAME_PREFIXES) {
if (typeName.startsWith(prefix)) {
return false;
}
}
}
}
return true;
}
public static List<String> getBlockedClasses() {
final List<String> blocked = new ArrayList<String>();
blocked.addAll(BLOCKED_CLASS_NAME_PREFIXES);
return blocked;
}
private ExpressionUtils() {
super();
}
}