quarkusio / quarkus

Quarkus: Supersonic Subatomic Java.
https://quarkus.io
Apache License 2.0
13.8k stars 2.68k forks source link

HTTP 404 with j_security_check randomly appears during authentication #30637

Open jakwarrior opened 1 year ago

jakwarrior commented 1 year ago

Describe the bug

I have a form based authentication on my application. Randomly, I have a 404 error with the url /j_security_check when a client send a POST message. Even after a restart of the server, the error can be here. I can't find any logic. Sometimes it works, sometimes it doesn't. It seems to be related to mutual TLS authentication. I want my server to only let through clients that have the correct certificates. So I add that line in my application.properties: quarkus.http.ssl.client-auth=request I don't see the error with mutual TLS authentication disabled.

Expected behavior

No 404 error during authentication

Actual behavior

A 404 error appears during authentication, the url /j_security_check cannot be found. With quarkus logs configured in debug mode, I can see this stacktrace:

DEBUG [org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext] (vert.x-eventloop-thread-7) Restarting handler chain for exception exception: javax.ws.rs.NotFoundException: HTTP 404 Not Found
        at org.jboss.resteasy.reactive.server.handlers.RestInitialHandler.handle(RestInitialHandler.java:71)
        at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.invokeHandler(QuarkusResteasyReactiveRequestContext.java:94)
        at org.jboss.resteasy.reactive.common.core.AbstractResteasyReactiveContext.run(AbstractResteasyReactiveContext.java:145)
        at org.jboss.resteasy.reactive.server.handlers.RestInitialHandler.beginProcessing(RestInitialHandler.java:48)
        at org.jboss.resteasy.reactive.server.vertx.ResteasyReactiveVertxHandler.handle(ResteasyReactiveVertxHandler.java:23)
        at org.jboss.resteasy.reactive.server.vertx.ResteasyReactiveVertxHandler.handle(ResteasyReactiveVertxHandler.java:10)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
        at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:84)
        at io.quarkus.vertx.http.runtime.StaticResourcesRecorder$2.handle(StaticResourcesRecorder.java:71)
        at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)
        at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:177)
        at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
        at io.quarkus.vertx.http.runtime.VertxHttpRecorder$6.handle(VertxHttpRecorder.java:435)
        at io.quarkus.vertx.http.runtime.VertxHttpRecorder$6.handle(VertxHttpRecorder.java:413)

It's just the beginning of the stacktrace.

How to Reproduce?

This is my application.properties:

quarkus.ssl.native=true
quarkus.http.ssl.certificate.key-store-file=data/keystore.pfx
quarkus.http.ssl.certificate.key-store-password=mypassword
quarkus.http.insecure-requests=redirect
quarkus.http.port=8081
quarkus.http.ssl-port=8082
quarkus.http.ssl.certificate.trust-store-file=data/truststore.jks
quarkus.http.ssl.certificate.trust-store-password=mypassword
quarkus.http.ssl.client-auth=request

quarkus.http.auth.form.enabled=true
quarkus.http.auth.form.redirect-after-login=false
quarkus.http.auth.form.error-page=/auth
quarkus.http.auth.form.login-page=/auth
quarkus.http.auth.form.cookie-name=myapp
quarkus.http.auth.form.post-location=/j_security_check
quarkus.http.auth.form.location-cookie=myapp-redirect-location
quarkus.http.auth.session.encryption-key=XXXXX
quarkus.http.auth.permission.default.paths=/*                              
quarkus.http.auth.permission.default.policy=authenticated

quarkus.security.users.embedded.enabled=true
quarkus.security.users.embedded.plain-text=true
quarkus.security.users.embedded.users.user=password

quarkus.http.cors=true
quarkus.http.cors.access-control-allow-credentials=true
quarkus.http.cors.origins=*
quarkus.http.cors.methods=get,post,put,head,options
quarkus.http.cors.headers=accept, authorization, content-type, x-requested-with

Output of uname -a or ver

Ubuntu 20.04

Output of java -version

Adoptium 11.0.15+10

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.15.3

Build tool (ie. output of mvnw --version or gradlew --version)

Maven 3.8.3

Additional information

No response

quarkus-bot[bot] commented 1 year ago

/cc @sberyozkin (security)

sberyozkin commented 1 year ago

@jakwarrior Can you please create a reproducer ? I wonder if the MTLS authentication mechanism is interfering somehow. Can you try to restrict the form authentication to specific request paths, for example, https://quarkus.io/guides/security-overview-concept#path-specific-authentication-mechanisms, the form authentication mechanism is form. Without such a restriction, since you have 2 authentication mechanisms, you may be having MTLS mechanism affecting the form requests

sberyozkin commented 1 year ago

This feature is also interesting because it is possible that both MTLS and for example basic or bearer token authentication must succeed, I don't think we have any tests combining MTLS.

sberyozkin commented 1 year ago

Assigning myself just to explore a bit later combining MTLS with other mechanisms. Michal, please keep an eye on the form auth related concerns here. I don't think it is issue specific to Form Auth, but just in case

jakwarrior commented 1 year ago

@jakwarrior Can you please create a reproducer ? I wonder if the MTLS authentication mechanism is interfering somehow. Can you try to restrict the form authentication to specific request paths, for example, https://quarkus.io/guides/security-overview-concept#path-specific-authentication-mechanisms, the form authentication mechanism is form. Without such a restriction, since you have 2 authentication mechanisms, you may be having MTLS mechanism affecting the form requests

Thanks @sberyozkin for your answer. I changed my configuration like this and it works well !

quarkus.http.ssl.client-auth=required
quarkus.http.auth.form.post-location=/auth/j_security_check
quarkus.http.auth.permission.default.paths=/*                              
quarkus.http.auth.permission.default.policy=authenticated
quarkus.http.auth.permission.form.paths=/auth/j_security_check
quarkus.http.auth.permission.form.policy=authenticated
quarkus.http.auth.permission.form.auth-mechanism=form

I try to make a reproducer as soon as I have free time.

sberyozkin commented 1 year ago

Thanks @jakwarrior, I think we have enough info now to confirm that both MTLS and in this case Form are competing. Looks like quarkus.http.ssl.client-auth=required is a problem in this case, i.e, if no client cert is present, MTLS should let other mechanisms handle the autentication

sberyozkin commented 1 year ago

Oh I see, so in the original description it is quarkus.http.ssl.client-auth=request, the client cert is optional.

jakwarrior commented 1 year ago

I had the same issue with quarkus.http.ssl.client-auth=request or quarkus.http.ssl.client-auth=required.