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