Description
Problem description
We want to "hide" certain class members (methods, fields, properties) so that they are not accessible from templates. The problem is based on a discussion about white-list / black-list of accessible class members.
One example is preventing that one might call
${obj.class}
or
${obj.getClass()}
Why
In our plugin system, FM-templates and objects accessible in the FM-Context are coming from external users and which are not our developers.
We need a way to forbid some methods and fields (blacklist approach) which are considered harmful or dangerous (like .getClass()).
What
We wish to be able to do two things:
- define a whitelist of classes, methods, fields which are allowed to be accessed
- define a blacklist of classes, methods, fields which are NEVER allowed to be accessed
- the blacklist also servers as a safety guard against developer mistakes, which mistakenly whitelisted something by accident
What is already there?
Freemarker currently has MethodAppearanceFineTuner which can be injected to the ObjectWrapper.
It allows you to e.g. prevent access to ${obj.getClass()} method like this:
objWrapper.setMethodAppearanceFineTuner(new MethodAppearanceFineTuner() { @Override public void process(MethodAppearanceDecisionInput in, MethodAppearanceDecision out) { if(in.getMethod().getName().contains("getClass")){ // hide method out.setExposeMethodAs(null); } } });
But currently it does not allow you to hide the property. That means ${obj.class} is still possible.
There is also something like freemarker.ext.beans.UnsafeMethods.isUnsafeMethod(Method) in the code base, which is missing .getClass() and cannot be changed because it wouldn't be backwards compatible.
A discussion with ddekany by email pointed in the direction:
the point that need to be customizable is ClassIntrospector.isAllowedToExpose.
How
The how is currently up for discussion. A very simplistic POC-approach using MethodAppearanceFineTuner can be found in this commit https://github.com/chrisrueger/freemarker/commit/a2ff9a7f1d474bdb7774e2d794812f1e6f7ae06b (only a base for discussion)
Keywords: Maybe a mix of different hooks for doing it programmatically (e.g. ClassIntrospector.isAllowedToExpose or similar to MethodAppearanceFineTuner), .properties files, annotations are coming to mind.
Side Note on OSGI / Classloaders
We are living in an OSGI-world of multiple bundles with each having a different class loader.
So it would be good to have a way to let other bundles (with different classloader) define their own rules / hooks too, without requiring the objectWrapper to know about the class added to freemarker. Maybe this OSGI part does not belong to this issue exactly but I wanted to bring it up as it might be a constraint for the solution.