JEP415: FilterInThread Example
Roger Riggs
roger.riggs at oracle.com
Mon Feb 6 14:48:34 UTC 2023
Thanks, I'd planned to file a bug too.
If you think of any improvements, let me know.
On 2/6/23 8:26 AM, Dr Heinz M. Kabutz wrote:
>
> FWIW, I've also submitted this as a bug report:
>
> https://bugs.java.com/bugdatabase/view_bug.do?bug_id=JDK-8301863
>
>
> Regards
>
> Heinz
> --
> Dr Heinz M. Kabutz (PhD CompSci)
> Author of "The Java™ Specialists' Newsletter" -www.javaspecialists.eu
> Java Champion -www.javachampions.org
> JavaOne Rock Star Speaker
> Tel: +30 69 75 595 262
> Skype: kabutz
> On 2023/02/06 06:55, Roger Riggs wrote:
>> Hi Heinz,
>>
>> Indeed, this example is not intuitive and does not do what was
>> intended and could use a better explanation.
>>
>> The interaction of three filters gets complicated and their
>> combination depends on the ordering and intention of each filter and
>> the particular filter factory goal. The FilterInThread example
>> provides only one of many possible functions.
>>
>> The FilterInThread example uses the JVM-wide filter, thread filter,
>> and stream filter for different purposes.
>>
>> The JVM-wide filter has a particular role in that it can be set on
>> the command line via a system property.
>> It is typically used as a backstop after the application is deployed
>> to patch in additional rejection of classes.
>> The property value syntax allows for either allowing or rejecting
>> classes, and an otherwise unmentioned class is left UNDECIDED,
>> possibly with some risk exposure.
>>
>> The thread filter is used to more focus de-serialization on a group
>> of classes, either to narrow it or expand it.
>>
>> The FilterInThread example takes the position that any UNDECIDED in
>> the thread's filter and the JVM-wide filter should be rejected even
>> if the pattern does not explicitly do so. This keeps an oversight in
>> filter construction from becoming a risk.
>>
>> The stream filter is included mostly for backward compatibility,
>> introduced in JDK 9 via JEP 290. The stream filter is set by the code
>> creating the ObjectInputStream and part of its design and purpose. In
>> the FilterInThread example, if it returns UNDECIDED, the result is
>> determined by a merge of the other two filters and further rejecting
>> UNDECIDED.
>>
>> The bug in the example, that individually rejects UNDECIDED in the
>> JVM-wide and thread filters respectively, should instead reject only
>> if both return UNDECIDED.
>>
>> The revised example is:
>>
>> *// Returns a composite filter of the static JVM-wide filter, a
>> thread-specific filter, *// and the stream-specific filter. *public
>> ObjectInputFilter apply(ObjectInputFilter curr, ObjectInputFilter
>> next) { *if (curr == null) { *// Called from the OIS constructor or
>> perhaps OIS.setObjectInputFilter with no current filter *var filter =
>> filterThreadLocal.get(); *if (filter != null) { *// Merge to invoke
>> the thread local filter and then the JVM-wide filter (if any) *filter
>> = ObjectInputFilter.merge(filter, next); *return
>> ObjectInputFilter.rejectUndecidedClass(filter); *} *return (next ==
>> null) ? null : ObjectInputFilter.rejectUndecidedClass(next); *} else
>> { *// Called from OIS.setObjectInputFilter with a current filter and
>> a stream-specific filter. *// The curr filter already incorporates
>> the thread filter and static JVM-wide filter *// and rejection of
>> undecided classes *// If there is a stream-specific filter merge to
>> invoke it and then the current filter. *if (next != null) { *return
>> ObjectInputFilter.merge(next, curr); *} *return curr; *} *}
>>
>> The filters are evaluated as:
>> merge(restrictLargeArrays,rejectUndecidedClass(merge(allowInteger,allowArrayList)))
>>
>> The first call to the factory returns a filter: `var f1 =
>> rejectUndecidedClass(merge(allowInteger,allowArrayList))`
>> The second call to the factory returns filter: `var f2 =
>> merge(restrictLargeArrays, f1)`
>>
>> The filters are evaluated in order, until an accept or reject is
>> returned:
>> 1) restrictLargeArrays (stream)
>> 2) allowInteger (thread filter)
>> 3) allowArrayList (JVM-wide filter)
>>
>> This has the same value as your ideal but without an extra
>> RejectUndecidedClass.
>>
>> Note that in this composition, the choice by a filter to accept or
>> reject can not be overridden by a subsequent filter.
>>
>> Thank you for the comments and suggestions, Roger
>>
>> On 2/3/23 1:20 PM, Dr Heinz M. Kabutz wrote:
>>> I was trying to get my head around the FilterInThread example in JEP
>>> 415 (https://openjdk.org/jeps/415) and the JavaDoc for the
>>> ObjectInputFilter
>>> (https://docs.oracle.com/en/java/javase/17/docs/api/java.base/java/io/ObjectInputFilter.html)
>>>
>>> For example, let's assume we have three filters. The first allow
>>> ArrayList, the second allows Integer, the third restricts arrays to
>>> not be larger than 1000.
>>>
>>> ObjectInputFilter allowArrayList = ObjectInputFilter.allowFilter(
>>> Set.of(ArrayList.class, Object.class)::contains, UNDECIDED
>>> );
>>> ObjectInputFilter allowInteger = ObjectInputFilter.allowFilter(
>>> Set.of(Number.class, Integer.class)::contains, UNDECIDED
>>> );
>>> ObjectInputFilter restrictLargeArrays =
>>> ObjectInputFilter.Config.createFilter("maxarray=1000");
>>>
>>> Let's say that we create a FilterInThread instance and install that
>>> as our factory. Furthermore, we set the allowArrayList as the global
>>> serial filter. When we call filterInThread.doWithSerialFilter() we
>>> pass in the allowInteger filter. Lastly, during the actual
>>> deserialization, we call setObjectInputFilter() on the
>>> ObjectInputStream with the restrictLargeArrays filter. Ideally, I
>>> would want the final filter to look like this:
>>>
>>> rejectUndecidedClass(merge(restrictLargeArrays,merge(allowInteger,allowArrayList)))
>>>
>>>
>>> However, in the FilterInThread example, we add the
>>> rejectUndecidedClass() wrapper around each of the steps. Thus we
>>> would get something like:
>>>
>>> rejectUndecidedClass(merge(restrictLargeArrays,rejectUndecidedClass(merge(allowInteger,rejectUndecidedClass(allowArrayList)))))
>>>
>>>
>>> Thus we could never allow any classes except for ArrayList.
>>>
>>>
>>> Regards
>>>
>>> Heinz
>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20230206/c6b2e3a4/attachment-0001.htm>
More information about the core-libs-dev
mailing list