Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow configuration of Jackson default typing #1330

Closed
saw303 opened this issue Mar 6, 2019 · 8 comments
Closed

Allow configuration of Jackson default typing #1330

saw303 opened this issue Mar 6, 2019 · 8 comments
Assignees
Labels
status: pr submitted A pull request has been submitted for the issue type: improvement A minor improvement to an existing feature
Milestone

Comments

@saw303
Copy link
Contributor

saw303 commented Mar 6, 2019

When using working on a Java JSON API that using polymorphism or inheritance Jackson requires some sort of discriminator to deserialize the JSON string back into the Java types.

That feature can be enabled by calling com.fasterxml.jackson.databind.ObjectMapper#enableDefaultTyping()

Please provide a way to enable this without writing a custom BeanCreatedEventListener.

@jameskleeh jameskleeh added the type: improvement A minor improvement to an existing feature label Mar 6, 2019
@jameskleeh jameskleeh changed the title Enable Jackson default typing Allow configuration of Jackson default typing Mar 6, 2019
@puneetbehl puneetbehl self-assigned this Mar 6, 2019
@saw303
Copy link
Contributor Author

saw303 commented Mar 7, 2019

@jameskleeh given the following Micronaut client.

@Client("/v1/")
public interface RootClient {

  @Post
  String createSession(RootPostResourceModel model);
}

and the RootPostResourceModel

@Generated(
    date = "2019-03-07T14:12:29.652904Z",
    comments = "Specification filename: root.v1.json",
    value = "ch.silviowangler.restapi"
)
public class RootPostResourceModel implements Serializable, ResourceModel {
  public static final String TYPE = "application/questionnaire.session";

  @NotNull
  private List<OfferType> offers = new java.util.ArrayList<>();

  public List<OfferType> getOffers() {
    return this.offers;
  }

  public void setOffers(List<OfferType> offers) {
    this.offers = offers;
  }

  @Override
  public boolean equals(Object other) {
    if (this == other) return true;
    if (! (other instanceof RootPostResourceModel)) return false;
    RootPostResourceModel that = (RootPostResourceModel) other;
    return Objects.equals(getOffers(), that.getOffers());
  }

  @Override
  public int hashCode() {
    return Objects.hash(offers);
  }
}

and enabled objectmapper.enableDefaultTyping() using a BeanCreatedEventListener like this

@Singleton
public class ObjectMapperInitializer implements BeanCreatedEventListener<ObjectMapper> {
  @Override
  public ObjectMapper onCreated(BeanCreatedEvent<ObjectMapper> event) {
    ObjectMapper bean = event.getBean();
    bean.enableDefaultTyping(ObjectMapper.DefaultTyping.NON_CONCRETE_AND_ARRAYS);
    return bean;
  }
}

I get an error when serializing the request.

16:59:00.245 [nioEventLoopGroup-1-4] ERROR i.m.h.s.netty.RoutingInBoundHandler - Unexpected error occurred: Error encoding object [ /model - Failed to convert argument [model] for value [null] due to: Cannot construct instance of `xyz.RootPostResourceModel` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('com.adcubum.gesus.questionnaire.web.v1.RootPostResourceModel')
 at [Source: UNKNOWN; line: -1, column: -1]] to JSON: Type id handling not implemented for type io.micronaut.core.value.OptionalMultiValuesMap (by serializer of type io.micronaut.jackson.serialize.OptionalValuesSerializer) (through reference chain: io.micronaut.http.hateos.JsonError["_links"])
io.micronaut.http.codec.CodecException: Error encoding object [ /model - Failed to convert argument [model] for value [null] due to: Cannot construct instance of `xyz.RootPostResourceModel` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('com.adcubum.gesus.questionnaire.web.v1.RootPostResourceModel')
 at [Source: UNKNOWN; line: -1, column: -1]] to JSON: Type id handling not implemented for type io.micronaut.core.value.OptionalMultiValuesMap (by serializer of type io.micronaut.jackson.serialize.OptionalValuesSerializer) (through reference chain: io.micronaut.http.hateos.JsonError["_links"])
	at io.micronaut.jackson.codec.JsonMediaTypeCodec.encode(JsonMediaTypeCodec.java:176)
	at io.micronaut.jackson.codec.JsonMediaTypeCodec.encode(JsonMediaTypeCodec.java:182)

It seems that Micronauts Jackson serializers are not ready for com.fasterxml.jackson.databind.ObjectMapper#enableDefaultTyping()

@puneetbehl
Copy link
Contributor

@saw303 please share RootPostResourceModel class or better a sample application.

puneetbehl added a commit that referenced this issue Mar 7, 2019
Added defaultTyping configuration for Jackson.
@puneetbehl puneetbehl added status: pr submitted A pull request has been submitted for the issue and removed status: in progress labels Mar 7, 2019
@saw303
Copy link
Contributor Author

saw303 commented Mar 7, 2019

@puneetbehl Added the RootPostResourceModel to my last comment above. Form the stacktrace I get the impression that it has not to do with my RootPostResourceModel since it is wrapped in that OptionalMultiValuesMap with the key model (param from the @Client method)

@puneetbehl
Copy link
Contributor

@saw303 Have you tried @JsonTypeInfo(use=JsonTypeInfo.Id.CLASS, include=JsonTypeInfo.As.PROPERTY, property="@class")?

Also, I am not sure about the above the but I am to serialize and deserialize using enableDefaultTyping. See the tests here

puneetbehl added a commit that referenced this issue Mar 11, 2019
Verify that configuration option for Jackson's defaultTyping is correctly converted and set on ObjectMapper.
puneetbehl added a commit that referenced this issue Mar 11, 2019
Removed the tests related to verify the behaviour of Jackson as they just add time it takes Micronaut to build.
@saw303
Copy link
Contributor Author

saw303 commented Mar 11, 2019

@puneetbehl sorry for answering late.

Putting annotation on classes is no option to me since they are part of another JAR that does not know Jackson/JSON at all.

puneetbehl added a commit that referenced this issue Mar 11, 2019
@jameskleeh jameskleeh added this to the 1.1.0 milestone Mar 11, 2019
@nhoughto
Copy link

nhoughto commented Apr 4, 2019

I'm still getting this error in 1.1.0.RC2 when enabling default typing jackson.defaultTyping=OBJECT_AND_NON_CONCRETE and call a HTTP url without a route that handles it, should produce an 404 error but instead I get:

Caused by: com.fasterxml.jackson.databind.exc.InvalidDefinitionException: Type id handling not implemented for type io.micronaut.core.value.OptionalMultiValuesMap (by serializer of type io.micronaut.jackson.serialize.OptionalValuesSerializer) (through reference chain: io.micronaut.http.hateoas.JsonError["_links"])
        at com.fasterxml.jackson.databind.exc.InvalidDefinitionException.from(InvalidDefinitionException.java:77)
        at com.fasterxml.jackson.databind.SerializerProvider.reportBadDefinition(SerializerProvider.java:1191)
        at com.fasterxml.jackson.databind.DatabindContext.reportBadDefinition(DatabindContext.java:313)
        at com.fasterxml.jackson.databind.JsonSerializer.serializeWithType(JsonSerializer.java:160)
        at com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:729)
        at com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:719)
        at com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:155)
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:480)
        at com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:319)
        at com.fasterxml.jackson.databind.ObjectMapper._configAndWriteValue(ObjectMapper.java:3905)
        at com.fasterxml.jackson.databind.ObjectMapper.writeValueAsBytes(ObjectMapper.java:3243)
        at io.micronaut.jackson.codec.JsonMediaTypeCodec.encode(JsonMediaTypeCodec.java:173)

same as OP

@nhoughto
Copy link

nhoughto commented Apr 4, 2019

Also the changes in 0d17b85 expose some configuration to enable default typing (useful for me), which itself warns of a deserialisation security risk and subsequent RCE. Is allowing this configuration via environment variables safe? If an attacker can set an environment variable they can then enable an insecure configuration that then exposes even a properly configured instance (as environment variables override standard configuration..).

@cowtowncoder
Copy link

Additional (late) note: Jackson 2.10.0 introduces new method, activateDefaultTyping() which allows safe use of Default Typing. See

FasterXML/jackson-databind#2195

for some more information. I would not recommend exposing existing "enableDefaultTyping()" if exposed to untrusted content, as per: https://medium.com/@cowtowncoder/on-jackson-cves-dont-panic-here-is-what-you-need-to-know-54cd0d6e8062

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
status: pr submitted A pull request has been submitted for the issue type: improvement A minor improvement to an existing feature
Projects
None yet
Development

No branches or pull requests

5 participants