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