micronaut-projects / micronaut-core

Micronaut Application Framework
http://micronaut.io
Apache License 2.0
6.09k stars 1.07k forks source link

Migration path: Server-side filters that need to read request bodies #7986

Open mrwilby opened 2 years ago

mrwilby commented 2 years ago

Feature description

In our security framework, we have a few unfortunate use cases where we need to be able to read the request body to determine authN/authZ context.

This was working fine in Micronaut 1.x via an HTTP server filter.

In 2.5, this breaking change was introduced: https://docs.micronaut.io/2.5.9/guide/#breaks


Micronaut 2.5

In previous versions of Micronaut it was possible to read the body of a request in a server filter under some conditions. Reading the request body in a filter has historically been inconsistent because the body is not read in many cases. In Micronaut 2.4, the body was read until the route arguments were satisfied, and then the server filters were executed. This lead to issues with memory leaks in some cases and is inefficient because a filter may skip route execution altogether by not proceeding the chain, thus the body did not need to be read. In Micronaut 2.5 the body will not be read until after filters are executed. This may lead to cases where the body was available in a filter and is no longer available.

We have migrated to v3.6.x and now see this breaking change impacting our test code.

What is the recommended approach to allow generic server-side filter components (e.g. code that runs inside the SecurityFilter or a custom server-side filter) to inspect the request body?

ThraaxSession commented 2 years ago

I've got the same issue with custom server-side filter. When I post my http body as JSON I can't read it as the body is always empty. It's also important that the JSON is generic. The content will be mapped then into a mutable map where I do some checks like the key is always a string and so on.

@graemerocher any idea as the issue is pretty old.

graemerocher commented 2 years ago

it is possible to implement a Netty channel handler that does the same thing by buffering the body for certain content types and then passing it downstream again but I agree we need an easier way for users to implement this. /cc @yawkat

dstepanov commented 2 years ago

I think this can be made optional like it's in resteasy.

ThraaxSession commented 2 years ago

If it takes longer time to implement it in HttpRequest<*> do you have an example @graemerocher to do with Netty channel handler?

mrwilby commented 2 years ago

In our scenario it would be ideal if the message body can be available only for certain annotated endpoints, rather than based upon content type. Not sure if feasible but sharing for consideration.

ThraaxSession commented 1 year ago

@graemerocher @yawkat any updates on this? I need at least a description how to implement the netty channel handler to get the request body.

ThraaxSession commented 1 year ago

Created a discussion to do it manually with netty channel handler: https://github.com/micronaut-projects/micronaut-core/discussions/8427

yawkat commented 1 year ago

I'm looking at filter improvements for 4.0 (see #8422) and may also add a facility to read the request body as a part of that, but there will be nothing before 4.0.

ThraaxSession commented 1 year ago

@yawkat any plan when 4.0 will be released?

Danke für deine Unterstützung Konrad! Viele Grüße Gino

yawkat commented 1 year ago

early next year probably

yawkat commented 1 year ago

filter improvements will make it into 4.0 but request body reading in filters probably won't

ThraaxSession commented 1 year ago

@yawkat so I would still need to implement an own netty pipeline? When we can expect the body directly in the http filter?

yawkat commented 1 year ago

i can give no timeline for it

graemerocher commented 1 year ago

See an example here on how to do this at the Netty level https://stackoverflow.com/a/75704441/259167