micronaut-security icon indicating copy to clipboard operation
micronaut-security copied to clipboard

Since Micronaut Security 4.6.8 route match is randomly null in the SecurityFilter

Open loicmathieu opened this issue 1 year ago • 32 comments

Expected Behavior

Migrating to 4.3.4 to 4.3.7 should not change the behavior of the Micronaut SecurityFilter.

Actual Behaviour

After migrating from 4.3.4 to 4.3.7, we started to see randomly routeMatch request attribute being null in the Micronaut SecurityFilter.

This has been seen using a debugger, see the following screenshot that show that routeMatch is null for a request GET /api.v1/demo/config but this endpoint is defined in our application so there should be a route match.

Dowgrading to 4.3.4 fixes the issue.

route-match-issue

Steps To Reproduce

No response

Environment Information

Java 17 Linux

Example Application

No response

Version

4.3.7

loicmathieu avatar Apr 15 '24 09:04 loicmathieu

The config endpoint is defined as is:

@Slf4j
@Controller("/api/v1")
public class MiscController {
    @Get("{/tenant}/configs")
    @ExecuteOn(TaskExecutors.IO)
    @Operation(tags = {"Misc"}, summary = "Get current configurations")
    public Configuration configuration() throws JsonProcessingException {
        // ...
    }
}

loicmathieu avatar Apr 15 '24 09:04 loicmathieu

don't see anything related to this other than documenting the route match behaviour in the diff https://github.com/micronaut-projects/micronaut-core/compare/v4.3.4...v4.3.7

Do you have steps to reproduce?

graemerocher avatar Apr 15 '24 09:04 graemerocher

@graemerocher indeed there isn't anything that seems to be able to cause such issue. We are rolling back to the old version of Micronaut, I'll confirm tomorrow if it fixes the issue then I'll try to create a reproducer but as it seems "random" this may be hard to reproduce.

loicmathieu avatar Apr 15 '24 09:04 loicmathieu

I can confirm that rolling back to 4.3.4 works in the environment where it causes the issue. I'll try to create a reproducer but as it seems "random" this may be hard to reproduce.

loicmathieu avatar Apr 16 '24 09:04 loicmathieu

FYI it's likely not core v4.3.4...v4.3.7 you need to look at, you need to look at the equivalent micronaut-core versions for those platform versions instead.

yawkat avatar Apr 16 '24 11:04 yawkat

so yeah this is the diff so it is between 4.3.9 and 4.3.12 of core

graemerocher avatar Apr 16 '24 13:04 graemerocher

https://github.com/micronaut-projects/micronaut-platform/compare/v4.3.4..v4.3.7

graemerocher avatar Apr 16 '24 13:04 graemerocher

not sure if there is much relevant there either https://github.com/micronaut-projects/micronaut-core/compare/v4.3.9...v4.3.12 🤔

graemerocher avatar Apr 16 '24 13:04 graemerocher

I think I reproduced this in a project. I don't have a reproducer yet. However, upgrading an application that uses session based authentication from 4.3.4 to 4.4.0 I started to unable login in production. Downgraded solved the issue.

not sure if there is much relevant there either v4.3.9...v4.3.12 🤔

Maybe something here: https://github.com/micronaut-projects/micronaut-core/commit/1ab87c5729965c7f3faef519ca544c874aa3ab1d This commits seems the only one touching the Router.

sdelamo avatar Apr 18 '24 21:04 sdelamo

@sdelamo can you find that commit where the regression exists?

graemerocher avatar Apr 19 '24 10:04 graemerocher

For my application, the solution was to force the usage of the io.micronaut.http.cookie.DefaultServerCookieEncoder via the creation of a file:

src/main/resources/META-INF/services/io.micronaut.http.cookie.ServerCookieEncoder

With content:

io.micronaut.http.cookie.DefaultServerCookieEncoder

After, #10435, which was part of Micronaut Core 4.1.13 the ServerCookieEncoder, the application was using io.micronaut.http.netty.cookies.NettyServerCookieEncoder. I am still investigating why NettyServerCookieEnconder fails to encode my session cookie.

Thus, I am might be seeing a completely different issues as @loicmathieu

sdelamo avatar Apr 23 '24 15:04 sdelamo

The last comment of @sdelamo is interesting, we had to switch to the ServerCookieDecoder implementation due to a bug in Micronaut 4 so we configured it to io.micronaut.http.netty.cookies.NettyLaxServerCookieDecoder.

As far as I remember the bug in the default ServerCookieDecoder was parsing issue with domain cookie, using the io.micronaut.http.netty.cookies.NettyLaxServerCookieDecoder fixes the issue.

loicmathieu avatar Apr 24 '24 07:04 loicmathieu

The reference issue we had we cookie parsing, it may be related to this issue: https://github.com/micronaut-projects/micronaut-core/issues/10435

loicmathieu avatar Apr 24 '24 07:04 loicmathieu

The last comment of @sdelamo is interesting, we had to switch to the ServerCookieDecoder implementation due to a bug in Micronaut 4 so we configured it to io.micronaut.http.netty.cookies.NettyLaxServerCookieDecoder.

Please, note that should not be longer necessary due to https://github.com/micronaut-projects/micronaut-core/pull/10659 if you are using core 4.3.13 or above.

As far as I remember the bug in the default ServerCookieDecoder was parsing issue with domain cookie, using the io.micronaut.http.netty.cookies.NettyLaxServerCookieDecoder fixes the issue.

I get the issue only when deploying to Amazon Elastic Beanstalk instead of locally. Thus, I think the cookie's domain part may be related, but I still need to get to the bottom of it.

sdelamo avatar Apr 24 '24 07:04 sdelamo

Just to confirm that I've tried with

  • 4.3.8, 4.4.1
  • with or without NettyLaxServerCookieDecoder or DefaultServerCookieEncoder

All failed at approximately 5% of the request, only the 4.3.4 fixed the issue. My feeling is the security-module is the main reason, but not sure.

tchiotludo avatar Apr 25 '24 21:04 tchiotludo

The issue may be in Micronaut Security, there was changes in the JWT token validator and we do use JWT tokens: https://github.com/micronaut-projects/micronaut-security/compare/v4.6.6...v4.6.9

loicmathieu avatar Apr 26 '24 07:04 loicmathieu

Don't know if it helps but we have the following cookie after login image

loicmathieu avatar Apr 26 '24 08:04 loicmathieu

We reproduce the issue on one of our preview environment with only the JWT cookie, no other cookie exists. As it's a preview env we can experiment if someone has an idea to dig deeper.

loicmathieu avatar Apr 26 '24 08:04 loicmathieu

could you try with a newer version of Micronaut but forcing an older version of Micronaut Security. If we can narrow it down there we at least know where to look.

graemerocher avatar Apr 26 '24 12:04 graemerocher

We're testing a bunch of things at the moment; we have a filter that executes before the security filter; if we move it after, it no longer fails.

We also plan to do exactly what you asking for, I'll keep you posted.

loicmathieu avatar Apr 26 '24 12:04 loicmathieu

@graemerocher, the first version of micronaut-security failing is the 4.6.8 I've update to micronaut-platform at 4.3.8, downgrading to micronaut-security to 4.6.7 at working well, starting from 4.6.8 I start to see errors. To have error, you need to siege any authenticated endpoint, since it's happen approximately 5%. First felling, this commit could be the reason: https://github.com/micronaut-projects/micronaut-security/commit/afd2f692a7cb2cb215f40e4e827ea4de91227139 (since we are using the JWT implementation)

tchiotludo avatar Apr 26 '24 13:04 tchiotludo

thanks for the feedback that helps a great deal

graemerocher avatar Apr 26 '24 13:04 graemerocher

Latest test before weekend: I use micronaut core at 4.3.8, I use this version and replaced the bean from micronaut-security 4.6.10 (see here) and no more error on local.
Will validate after build on our preview env.

tchiotludo avatar Apr 26 '24 20:04 tchiotludo

we can't see that commit

graemerocher avatar Apr 26 '24 22:04 graemerocher

It's just this file with a @Replaces to overload the micronaut bean from latest version

tchiotludo avatar Apr 27 '24 07:04 tchiotludo

It's just this file with a @Replaces to overload the micronaut bean from latest version

Thanks @tchiotludo I will try to revert the changes we did lately to that file tomorrow and see if it helps.

sdelamo avatar Apr 28 '24 17:04 sdelamo

@tchiotludo just to confirm:

If you set, it works ✅:

public class JwtTokenValidator<T> implements TokenValidator<T> {
...
   public Publisher<Authentication> validateToken(String token, @Nullable T request) {
        return validator.validate(token, request)
                .flatMap(jwtAuthenticationFactory::createAuthentication)
                .map(Flux::just)
                .orElse(Flux.empty());
    }
}
}

if you set, as we do currently it fails ❌:

public class JwtTokenValidator<T> implements TokenValidator<T> {
...
   public Publisher<Authentication> validateToken(String token, @Nullable T request) {
return Mono.fromCallable(() -> validator.validate(token, request))
            .flatMap(tokenOptional -> tokenOptional.flatMap(jwtAuthenticationFactory::createAuthentication)
                .map(Mono::just).orElse(Mono.empty())).subscribeOn(scheduler);
}
}

Is that so?

Aside, Do you have io.micrometer:context-propagation in your classpath for Reactor context propagation?

sdelamo avatar Apr 29 '24 08:04 sdelamo

  • Yes it seems that only the first one works (as I see on the diff between both files, this look like the only relevant changes).
  • We don't have any context-propagation on the classpath.

tchiotludo avatar Apr 29 '24 11:04 tchiotludo

If I analyze our Gradle dependency graph, context-propagation is a transitive dependency of micronaut-runtime and micronaut-http, so even if we didn't have a direct reference to it, it should be included.

loicmathieu avatar Apr 29 '24 12:04 loicmathieu

are you sure you are not confusing micronaut-context-propagation which is transitive of micronaut-runtime with io.micrometer:context-propagation?

graemerocher avatar Apr 29 '24 12:04 graemerocher