1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
|
package com.fasterxml.jackson.databind.jsontype;
import java.util.HashSet;
import java.util.Set;
import com.fasterxml.jackson.databind.JavaType;
import com.fasterxml.jackson.databind.cfg.MapperConfig;
/**
* {@link PolymorphicTypeValidator} that will only allow polymorphic handling if
* the base type is NOT one of potential dangerous base types (see {@link #isUnsafeBaseType}
* for specific list of such base types). No further validation is performed on subtype.
*<p>
* Note that when using potentially unsafe base type like {@link java.lang.Object} a custom
* implementation (or subtype with override) is needed. Most commonly subclasses would
* override both {@link #isUnsafeBaseType} and {@link #isSafeSubType}: former to allow
* all (or just more) base types, and latter to add actual validation of subtype.
*
* @since 2.11
*/
public class DefaultBaseTypeLimitingValidator
extends PolymorphicTypeValidator
implements java.io.Serializable
{
private static final long serialVersionUID = 1L;
@Override
public Validity validateBaseType(MapperConfig<?> config, JavaType baseType)
{
// Immediately block potentially unsafe base types
if (isUnsafeBaseType(config, baseType)) {
return Validity.DENIED;
}
// otherwise indicate that type may be ok (so further calls are made --
// does not matter with base implementation but allows easier sub-classing)
return Validity.INDETERMINATE;
}
@Override
public Validity validateSubClassName(MapperConfig<?> config,
JavaType baseType, String subClassName) {
// return INDETERMINATE just for easier sub-classing
return Validity.INDETERMINATE;
}
@Override
public Validity validateSubType(MapperConfig<?> config, JavaType baseType,
JavaType subType)
{
return isSafeSubType(config, baseType, subType)
? Validity.ALLOWED
: Validity.DENIED;
}
/**
* Helper method called to determine if the given base type is known to be
* problematic regarding possible "gadget types".
* Currently includes following types:
*<ul>
* <li>{@link java.lang.Object}</li>
* <li>{@link java.io.Closeable}</li>
* <li>{@link java.io.Serializable}</li>
* <li>{@link java.lang.AutoCloseable}</li>
* <li>{@link java.lang.Cloneable}</li>
* <li>{@link java.util.logging.Handler}</li>
* <li>{@link javax.naming.Referenceable}</li>
* <li>{@link javax.sql.DataSource}</li>
*</ul>
* which are JDK-included super types of at least one gadget type (not necessarily
* included in JDK)
*
* @param config Current mapper configuration
* @param baseType Base type to test
*/
protected boolean isUnsafeBaseType(MapperConfig<?> config, JavaType baseType)
{
return UnsafeBaseTypes.instance.isUnsafeBaseType(baseType.getRawClass());
}
/**
* Helper called to determine whether given actual subtype is considered safe
* to process: this will only be called if subtype was considered acceptable
* earlier.
*
* @param config Current mapper configuration
* @param baseType Base type of sub type (validated earlier)
* @param subType Sub type to test
*/
protected boolean isSafeSubType(MapperConfig<?> config,
JavaType baseType, JavaType subType)
{
return true;
}
private final static class UnsafeBaseTypes {
public final static UnsafeBaseTypes instance = new UnsafeBaseTypes();
private final Set<String> UNSAFE = new HashSet<>();
{
// first add names of types in `java.base`
UNSAFE.add(Object.class.getName());
UNSAFE.add(java.io.Closeable.class.getName());
UNSAFE.add(java.io.Serializable.class.getName());
UNSAFE.add(AutoCloseable.class.getName());
UNSAFE.add(Cloneable.class.getName());
// and then couple others typically included in JDK, but that we
// prefer not adding direct reference to
UNSAFE.add("java.util.logging.Handler");
UNSAFE.add("javax.naming.Referenceable");
UNSAFE.add("javax.sql.DataSource");
}
public boolean isUnsafeBaseType(Class<?> rawBaseType)
{
return UNSAFE.contains(rawBaseType.getName());
}
}
}
|