From 01ed12c853f234f3731095c6cc32265c0aa6d799 Mon Sep 17 00:00:00 2001 From: Tatu Saloranta Date: Mon, 29 Apr 2019 22:17:03 -0700 Subject: [PATCH] More work on #2195 --- .../jackson/databind/ObjectMapper.java | 143 +++++++++++------- .../jackson/databind/cfg/MapperBuilder.java | 88 +++++++++++ .../vld/ValidatePolymSubTypeTest.java | 10 +- 3 files changed, 184 insertions(+), 57 deletions(-) diff --git a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java index 8706758a92..6e3c00514f 100644 --- a/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java +++ b/src/main/java/com/fasterxml/jackson/databind/ObjectMapper.java @@ -1525,7 +1525,43 @@ public ObjectMapper setDefaultMergeable(Boolean b) { /* /********************************************************** - /* Type information configuration + /* Subtype registration + /********************************************************** + */ + + /** + * Method for registering specified class as a subtype, so that + * typename-based resolution can link supertypes to subtypes + * (as an alternative to using annotations). + * Type for given class is determined from appropriate annotation; + * or if missing, default name (unqualified class name) + */ + public void registerSubtypes(Class... classes) { + getSubtypeResolver().registerSubtypes(classes); + } + + /** + * Method for registering specified class as a subtype, so that + * typename-based resolution can link supertypes to subtypes + * (as an alternative to using annotations). + * Name may be provided as part of argument, but if not will + * be based on annotations or use default name (unqualified + * class name). + */ + public void registerSubtypes(NamedType... types) { + getSubtypeResolver().registerSubtypes(types); + } + + /** + * @since 2.9 + */ + public void registerSubtypes(Collection> subtypes) { + getSubtypeResolver().registerSubtypes(subtypes); + } + + /* + /********************************************************** + /* Default typing (automatic polymorphic types): current (2.10) /********************************************************** */ @@ -1535,14 +1571,13 @@ public ObjectMapper setDefaultMergeable(Boolean b) { * enableDefaultTyping(DefaultTyping.OBJECT_AND_NON_CONCRETE); * *

- * NOTE: use of Default Typing can be a potential security risk if incoming - * content comes from untrusted sources, and it is recommended that this - * is either not done, or, if enabled, use {@link #setDefaultTyping} - * passing a custom {@link TypeResolverBuilder} implementation that white-lists - * legal types to use. + * NOTE: choice of {@link PolymorphicTypeValidator} to pass is critical for security + * as allowing all subtypes can be risky for untrusted content. + * + * @since 2.10 */ - public ObjectMapper enableDefaultTyping() { - return enableDefaultTyping(DefaultTyping.OBJECT_AND_NON_CONCRETE); + public ObjectMapper enableDefaultTyping(PolymorphicTypeValidator ptv) { + return enableDefaultTyping(ptv, DefaultTyping.OBJECT_AND_NON_CONCRETE); } /** @@ -1551,14 +1586,14 @@ public ObjectMapper enableDefaultTyping() { * enableDefaultTyping(dti, JsonTypeInfo.As.WRAPPER_ARRAY); * *

- * NOTE: use of Default Typing can be a potential security risk if incoming - * content comes from untrusted sources, and it is recommended that this - * is either not done, or, if enabled, use {@link #setDefaultTyping} - * passing a custom {@link TypeResolverBuilder} implementation that white-lists - * legal types to use. + * NOTE: choice of {@link PolymorphicTypeValidator} to pass is critical for security + * as allowing all subtypes can be risky for untrusted content. + * + * @since 2.10 */ - public ObjectMapper enableDefaultTyping(DefaultTyping dti) { - return enableDefaultTyping(dti, JsonTypeInfo.As.WRAPPER_ARRAY); + public ObjectMapper enableDefaultTyping(PolymorphicTypeValidator ptv, + DefaultTyping dti) { + return enableDefaultTyping(ptv, dti, JsonTypeInfo.As.WRAPPER_ARRAY); } /** @@ -1570,26 +1605,24 @@ public ObjectMapper enableDefaultTyping(DefaultTyping dti) { * and attempts of do so will throw an {@link IllegalArgumentException} to make * this limitation explicit. *

- * NOTE: use of Default Typing can be a potential security risk if incoming - * content comes from untrusted sources, and it is recommended that this - * is either not done, or, if enabled, use {@link #setDefaultTyping} - * passing a custom {@link TypeResolverBuilder} implementation that white-lists - * legal types to use. + * NOTE: choice of {@link PolymorphicTypeValidator} to pass is critical for security + * as allowing all subtypes can be risky for untrusted content. * * @param applicability Defines kinds of types for which additional type information * is added; see {@link DefaultTyping} for more information. + * + * @since 2.10 */ - public ObjectMapper enableDefaultTyping(DefaultTyping applicability, JsonTypeInfo.As includeAs) + public ObjectMapper enableDefaultTyping(PolymorphicTypeValidator ptv, + DefaultTyping applicability, JsonTypeInfo.As includeAs) { - /* 18-Sep-2014, tatu: Let's add explicit check to ensure no one tries to - * use "As.EXTERNAL_PROPERTY", since that will not work (with 2.5+) - */ + // 18-Sep-2014, tatu: Let's add explicit check to ensure no one tries to + // use "As.EXTERNAL_PROPERTY", since that will not work (with 2.5+) if (includeAs == JsonTypeInfo.As.EXTERNAL_PROPERTY) { throw new IllegalArgumentException("Cannot use includeAs of "+includeAs); } - TypeResolverBuilder typer = _constructDefaultTypeResolverBuilder(applicability, - getPolymorphicTypeValidator()); + TypeResolverBuilder typer = _constructDefaultTypeResolverBuilder(applicability, ptv); // we'll always use full class name, when using defaulting typer = typer.init(JsonTypeInfo.Id.CLASS, null); typer = typer.inclusion(includeAs); @@ -1604,13 +1637,13 @@ public ObjectMapper enableDefaultTyping(DefaultTyping applicability, JsonTypeInf * to use for inclusion (default being "@class" since default type information * always uses class name as type identifier) *

- * NOTE: use of Default Typing can be a potential security risk if incoming - * content comes from untrusted sources, and it is recommended that this - * is either not done, or, if enabled, use {@link #setDefaultTyping} - * passing a custom {@link TypeResolverBuilder} implementation that white-lists - * legal types to use. + * NOTE: choice of {@link PolymorphicTypeValidator} to pass is critical for security + * as allowing all subtypes can be risky for untrusted content. + * + * @since 2.10 */ - public ObjectMapper enableDefaultTypingAsProperty(DefaultTyping applicability, String propertyName) + public ObjectMapper enableDefaultTypingAsProperty(PolymorphicTypeValidator ptv, + DefaultTyping applicability, String propertyName) { TypeResolverBuilder typer = _constructDefaultTypeResolverBuilder(applicability, getPolymorphicTypeValidator()); @@ -1641,7 +1674,7 @@ public ObjectMapper disableDefaultTyping() { * content comes from untrusted sources, so care should be taken to use * a {@link TypeResolverBuilder} that can limit allowed classes to * deserialize. - * + * * @param typer Type information inclusion handler */ public ObjectMapper setDefaultTyping(TypeResolverBuilder typer) { @@ -1650,34 +1683,42 @@ public ObjectMapper setDefaultTyping(TypeResolverBuilder typer) { return this; } + /* + /********************************************************** + /* Default typing (automatic polymorphic types): deprecated (pre-2.10) + /********************************************************** + */ + /** - * Method for registering specified class as a subtype, so that - * typename-based resolution can link supertypes to subtypes - * (as an alternative to using annotations). - * Type for given class is determined from appropriate annotation; - * or if missing, default name (unqualified class name) + * @deprecated Since 2.10 use {@link #enableDefaultTyping(PolymorphicTypeValidator)} instead */ - public void registerSubtypes(Class... classes) { - getSubtypeResolver().registerSubtypes(classes); + @Deprecated + public ObjectMapper enableDefaultTyping() { + return enableDefaultTyping(getPolymorphicTypeValidator()); } /** - * Method for registering specified class as a subtype, so that - * typename-based resolution can link supertypes to subtypes - * (as an alternative to using annotations). - * Name may be provided as part of argument, but if not will - * be based on annotations or use default name (unqualified - * class name). + * @deprecated Since 2.10 use {@link #enableDefaultTyping(PolymorphicTypeValidator,DefaultTyping)} instead */ - public void registerSubtypes(NamedType... types) { - getSubtypeResolver().registerSubtypes(types); + @Deprecated + public ObjectMapper enableDefaultTyping(DefaultTyping dti) { + return enableDefaultTyping(dti, JsonTypeInfo.As.WRAPPER_ARRAY); } /** - * @since 2.9 + * @deprecated Since 2.10 use {@link #enableDefaultTyping(PolymorphicTypeValidator,DefaultTyping,JsonTypeInfo.As)} instead */ - public void registerSubtypes(Collection> subtypes) { - getSubtypeResolver().registerSubtypes(subtypes); + @Deprecated + public ObjectMapper enableDefaultTyping(DefaultTyping applicability, JsonTypeInfo.As includeAs) { + return enableDefaultTyping(getPolymorphicTypeValidator(), applicability, includeAs); + } + + /** + * @deprecated Since 2.10 use {@link #enableDefaultTypingAsProperty(PolymorphicTypeValidator,DefaultTyping,String)} instead + */ + @Deprecated + public ObjectMapper enableDefaultTypingAsProperty(DefaultTyping applicability, String propertyName) { + return enableDefaultTypingAsProperty(getPolymorphicTypeValidator(), applicability, propertyName); } /* diff --git a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java index b7c20ffed7..42a64e76e5 100644 --- a/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java +++ b/src/main/java/com/fasterxml/jackson/databind/cfg/MapperBuilder.java @@ -7,9 +7,11 @@ import com.fasterxml.jackson.annotation.JsonAutoDetect; import com.fasterxml.jackson.annotation.JsonInclude; +import com.fasterxml.jackson.annotation.JsonTypeInfo; import com.fasterxml.jackson.annotation.PropertyAccessor; import com.fasterxml.jackson.core.*; import com.fasterxml.jackson.databind.*; +import com.fasterxml.jackson.databind.ObjectMapper.DefaultTyping; import com.fasterxml.jackson.databind.deser.*; import com.fasterxml.jackson.databind.introspect.VisibilityChecker; import com.fasterxml.jackson.databind.jsontype.NamedType; @@ -556,6 +558,92 @@ public B polymorphicTypeValidator(PolymorphicTypeValidator ptv) { return _this(); } + /* + /********************************************************************** + /* Default typing + /********************************************************************** + */ + + /** + * Convenience method that is equivalent to calling + *

+     *  enableDefaultTyping(subtypeValidator, DefaultTyping.OBJECT_AND_NON_CONCRETE);
+     *
+ *

+ * NOTE: choice of {@link PolymorphicTypeValidator} to pass is critical for security + * as allowing all subtypes can be risky for untrusted content. + */ + public B enableDefaultTyping(PolymorphicTypeValidator subtypeValidator) { + _mapper.enableDefaultTyping(subtypeValidator); + return _this(); + } + + /** + * Convenience method that is equivalent to calling + *

+     *  enableDefaultTyping(subtypeValidator, dti, JsonTypeInfo.As.WRAPPER_ARRAY);
+     *
+ *

+ * NOTE: choice of {@link PolymorphicTypeValidator} to pass is critical for security + * as allowing all subtypes can be risky for untrusted content. + */ + public B enableDefaultTyping(PolymorphicTypeValidator subtypeValidator, + DefaultTyping dti) { + _mapper.enableDefaultTyping(subtypeValidator, dti); + return _this(); + } + + /** + * Method for enabling automatic inclusion of type information, needed + * for proper deserialization of polymorphic types (unless types + * have been annotated with {@link com.fasterxml.jackson.annotation.JsonTypeInfo}). + *

+ * NOTE: use of JsonTypeInfo.As#EXTERNAL_PROPERTY NOT SUPPORTED; + * and attempts of do so will throw an {@link IllegalArgumentException} to make + * this limitation explicit. + *

+ * NOTE: choice of {@link PolymorphicTypeValidator} to pass is critical for security + * as allowing all subtypes can be risky for untrusted content. + * + * @param applicability Defines kinds of types for which additional type information + * is added; see {@link DefaultTyping} for more information. + */ + public B enableDefaultTyping(PolymorphicTypeValidator subtypeValidator, + DefaultTyping applicability, JsonTypeInfo.As includeAs) + { + _mapper.enableDefaultTyping(subtypeValidator, applicability, includeAs); + return _this(); + } + + /** + * Method for enabling automatic inclusion of type information -- needed + * for proper deserialization of polymorphic types (unless types + * have been annotated with {@link com.fasterxml.jackson.annotation.JsonTypeInfo}) -- + * using "As.PROPERTY" inclusion mechanism and specified property name + * to use for inclusion (default being "@class" since default type information + * always uses class name as type identifier) + *

+ * NOTE: choice of {@link PolymorphicTypeValidator} to pass is critical for security + * as allowing all subtypes can be risky for untrusted content. + */ + public B enableDefaultTypingAsProperty(PolymorphicTypeValidator subtypeValidator, + DefaultTyping applicability, String propertyName) + { + _mapper.enableDefaultTypingAsProperty(subtypeValidator, applicability, propertyName); + return _this(); + } + + /** + * Method for disabling automatic inclusion of type information; if so, only + * explicitly annotated types (ones with + * {@link com.fasterxml.jackson.annotation.JsonTypeInfo}) will have + * additional embedded type information. + */ + public B disableDefaultTyping() { + _mapper.disableDefaultTyping(); + return _this(); + } + /* /********************************************************************** /* Other helper methods diff --git a/src/test/java/com/fasterxml/jackson/databind/jsontype/vld/ValidatePolymSubTypeTest.java b/src/test/java/com/fasterxml/jackson/databind/jsontype/vld/ValidatePolymSubTypeTest.java index 72bb3c8eb1..8e4ac84863 100644 --- a/src/test/java/com/fasterxml/jackson/databind/jsontype/vld/ValidatePolymSubTypeTest.java +++ b/src/test/java/com/fasterxml/jackson/databind/jsontype/vld/ValidatePolymSubTypeTest.java @@ -113,14 +113,12 @@ public Validity validateSubType(MapperConfig ctxt, JavaType baseType, JavaTyp // // // Mappers with Default Typing private final ObjectMapper MAPPER_DEF_TYPING_NAME_CHECK = jsonMapperBuilder() - .polymorphicTypeValidator(new SimpleNameBasedValidator()) - .build() - .enableDefaultTyping(); + .enableDefaultTyping(new SimpleNameBasedValidator()) + .build(); private final ObjectMapper MAPPER_DEF_TYPING_CLASS_CHECK = jsonMapperBuilder() - .polymorphicTypeValidator(new SimpleClassBasedValidator()) - .build() - .enableDefaultTyping(); + .enableDefaultTyping(new SimpleClassBasedValidator()) + .build(); // // // Mappers without Default Typing (explicit annotation needed)