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

"Request has already been read" using vertx + auth #23360

Closed
rolintoucour opened this issue Feb 2, 2022 · 21 comments · Fixed by #31129
Closed

"Request has already been read" using vertx + auth #23360

rolintoucour opened this issue Feb 2, 2022 · 21 comments · Fixed by #31129
Assignees
Labels
area/security kind/bug Something isn't working
Milestone

Comments

@rolintoucour
Copy link

Describe the bug

When I use a vertx Verticle route + jdbc authent, I got an error java.lang.IllegalStateException: Request has already been read.

I repeated the issue in a minimalist project that sets up a Verticle + JDBC authent.

When I comment the line quarkus.http.auth.permission.roles1.paths=/* then the error disappears.

My interpretation is that BodyHandler must be attached at first in a router, thus using jdbc-authent it reads the body before I can attach the BodyHandler. However as the router is injected into my verticle, I have no way to do it (maybe I am totally wrong).

Expected behavior

It shouldn't throw an exception. Using jdbc-auth, I should be able to read the body of requests from my verticle router's handlers.

Actual behavior

It throws the following exception:

2022-02-02 09:26:04,963 ERROR [io.qua.ver.htt.run.QuarkusErrorHandler] (executor-thread-0) HTTP Request to /test failed, error id: 7f4953c3-e074-43b7-8fa5-e1d069ffc4cd-1: java.lang.IllegalStateException: Request has already been read
	at io.vertx.core.http.impl.Http1xServerRequest.checkEnded(Http1xServerRequest.java:651)
	at io.vertx.core.http.impl.Http1xServerRequest.endHandler(Http1xServerRequest.java:338)
	at io.quarkus.vertx.http.runtime.ResumingRequestWrapper.endHandler(ResumingRequestWrapper.java:48)
	at io.vertx.ext.web.impl.HttpServerRequestWrapper.endHandler(HttpServerRequestWrapper.java:128)
	at io.vertx.ext.web.handler.impl.BodyHandlerImpl.handle(BodyHandlerImpl.java:86)
	at io.vertx.ext.web.handler.impl.BodyHandlerImpl.handle(BodyHandlerImpl.java:44)
	at io.vertx.reactivex.ext.web.handler.BodyHandler.handle(BodyHandler.java:94)
	at io.vertx.reactivex.ext.web.handler.BodyHandler.handle(BodyHandler.java:50)
	at io.vertx.reactivex.ext.web.Route$1.handle(Route.java:181)
	at io.vertx.reactivex.ext.web.Route$1.handle(Route.java:179)
	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1193)
	at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
	at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
	at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:362)
	at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:340)
	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1193)
	at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
	at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
	at io.quarkus.vertx.http.runtime.security.HttpAuthorizer.doPermissionCheck(HttpAuthorizer.java:121)
	at io.quarkus.vertx.http.runtime.security.HttpAuthorizer$2.accept(HttpAuthorizer.java:138)
	at io.quarkus.vertx.http.runtime.security.HttpAuthorizer$2.accept(HttpAuthorizer.java:127)
	at io.smallrye.context.impl.wrappers.SlowContextualConsumer.accept(SlowContextualConsumer.java:21)
	at io.smallrye.mutiny.helpers.UniCallbackSubscriber.onItem(UniCallbackSubscriber.java:72)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:60)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem$KnownItemSubscription.forward(UniCreateFromKnownItem.java:38)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem$KnownItemSubscription.access$100(UniCreateFromKnownItem.java:26)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem.subscribe(UniCreateFromKnownItem.java:23)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.performInnerSubscription(UniOnItemTransformToUni.java:81)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:57)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransform$UniOnItemTransformProcessor.onItem(UniOnItemTransform.java:43)
	at io.smallrye.mutiny.operators.uni.UniMemoizeOp.subscribe(UniMemoizeOp.java:66)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransform.subscribe(UniOnItemTransform.java:22)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni.subscribe(UniOnItemTransformToUni.java:25)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.groups.UniSubscribe.withSubscriber(UniSubscribe.java:50)
	at io.smallrye.mutiny.groups.UniSubscribe.with(UniSubscribe.java:90)
	at io.quarkus.vertx.http.runtime.security.HttpAuthorizer.doPermissionCheck(HttpAuthorizer.java:127)
	at io.quarkus.vertx.http.runtime.security.HttpAuthorizer.checkPermission(HttpAuthorizer.java:104)
	at io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder$3.handle(HttpSecurityRecorder.java:227)
	at io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder$3.handle(HttpSecurityRecorder.java:219)
	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1193)
	at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
	at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
	at io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder$2$2.onItem(HttpSecurityRecorder.java:152)
	at io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder$2$2.onItem(HttpSecurityRecorder.java:113)
	at io.smallrye.mutiny.operators.uni.UniMemoizeOp.drain(UniMemoizeOp.java:152)
	at io.smallrye.mutiny.operators.uni.UniMemoizeOp.onItem(UniMemoizeOp.java:172)
	at io.smallrye.mutiny.operators.uni.builders.DefaultUniEmitter.complete(DefaultUniEmitter.java:36)
	at io.quarkus.security.runtime.QuarkusIdentityProviderManagerImpl$1$1$1$1.run(QuarkusIdentityProviderManagerImpl.java:58)
	at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:543)
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:833)

How to Reproduce?

  1. Check out https://github.com/rolintoucour/quarkus_request_already_read
  2. Launch test GreetingResourceTest.testHelloEndpoint()
  3. Check the log
  4. Uncomment the property quarkus.http.auth.permission.roles1.paths=/*
  5. Test now passes fine

Output of uname -a or ver

Linux netwave-lolo 5.4.0-86-generic #97-Ubuntu SMP Fri Sep 17 19:19:40 UTC 2021 x86_64 x86_64 x86_64 GNU/Linux

Output of java -version

openjdk 17 2021-09-14 OpenJDK Runtime Environment Temurin-17+35 (build 17+35) OpenJDK 64-Bit Server VM Temurin-17+35 (build 17+35, mixed mode, sharing)

GraalVM version (if different from Java)

No response

Quarkus version or git rev

2.6.3

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

No response

Additional information

No response

@sberyozkin
Copy link
Member

CC @stuartwdouglas

@geoand
Copy link
Contributor

geoand commented Feb 7, 2022

I tried this and the tests pass...

Are you able to consistently reproduce this problem?

@rolintoucour
Copy link
Author

Yes, I always have the issue. Maybe it is related to my system in some way.

@rolintoucour
Copy link
Author

rolintoucour commented Feb 14, 2022

I can reproduce the issue consistently with a VM on GCP, if that might help:

  • I create a VM of type e2-small
  • in zone europe-west1-b
  • using image ubuntu 20.04 (ubuntu-2004-focal-v20220204)
  • basic setup otherwise

Then on the this VM I run the following:

sudo apt update && sudo apt upgrade
sudo apt install wget
wget https://github.com/adoptium/temurin17-binaries/releases/download/jdk-17.0.1%2B12/OpenJDK17U-jdk_x64_linux_hotspot_17.0.1_12.tar.gz
tar -xvf OpenJDK17U-jdk_x64_linux_hotspot_17.*.tar.gz
sudo mv jdk-17.0.1+12 /opt/
export JAVA_HOME=/opt/jdk-17.0.1+12
export PATH=$PATH:$JAVA_HOME/bin 

curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/ubuntu \
  $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt-get update
sudo apt-get install docker-ce docker-ce-cli containerd.io
sudo chmod 777 /var/run/docker.sock

git clone https://github.com/rolintoucour/quarkus_request_already_read
cd quarkus_request_already_read/
./mvnw clean test

The error logged is:

2022-02-14 14:45:04,881 ERROR [io.qua.ver.htt.run.QuarkusErrorHandler] (executor-thread-0) HTTP Request to /test failed, error id: 4d434897-2fee-4062-82b7-ba9fa783f5d0-1: java.lang.IllegalStateException: Request has already been read
	at io.vertx.core.http.impl.Http1xServerRequest.checkEnded(Http1xServerRequest.java:651)
	at io.vertx.core.http.impl.Http1xServerRequest.endHandler(Http1xServerRequest.java:338)
	at io.quarkus.vertx.http.runtime.ResumingRequestWrapper.endHandler(ResumingRequestWrapper.java:48)
	at io.vertx.ext.web.impl.HttpServerRequestWrapper.endHandler(HttpServerRequestWrapper.java:128)
	at io.vertx.ext.web.handler.impl.BodyHandlerImpl.handle(BodyHandlerImpl.java:86)
	at io.vertx.ext.web.handler.impl.BodyHandlerImpl.handle(BodyHandlerImpl.java:44)
	at io.vertx.reactivex.ext.web.handler.BodyHandler.handle(BodyHandler.java:94)
	at io.vertx.reactivex.ext.web.handler.BodyHandler.handle(BodyHandler.java:50)
	at io.vertx.reactivex.ext.web.Route$1.handle(Route.java:181)
	at io.vertx.reactivex.ext.web.Route$1.handle(Route.java:179)
	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1193)
	at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
	at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
	at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:362)
	at io.quarkus.vertx.http.runtime.VertxHttpRecorder$5.handle(VertxHttpRecorder.java:340)
	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1193)
	at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
	at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
	at io.quarkus.vertx.http.runtime.security.HttpAuthorizer.doPermissionCheck(HttpAuthorizer.java:121)
	at io.quarkus.vertx.http.runtime.security.HttpAuthorizer$2.accept(HttpAuthorizer.java:138)
	at io.quarkus.vertx.http.runtime.security.HttpAuthorizer$2.accept(HttpAuthorizer.java:127)
	at io.smallrye.context.impl.wrappers.SlowContextualConsumer.accept(SlowContextualConsumer.java:21)
	at io.smallrye.mutiny.helpers.UniCallbackSubscriber.onItem(UniCallbackSubscriber.java:72)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:60)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem$KnownItemSubscription.forward(UniCreateFromKnownItem.java:38)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem$KnownItemSubscription.access$100(UniCreateFromKnownItem.java:26)
	at io.smallrye.mutiny.operators.uni.builders.UniCreateFromKnownItem.subscribe(UniCreateFromKnownItem.java:23)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.performInnerSubscription(UniOnItemTransformToUni.java:81)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni$UniOnItemTransformToUniProcessor.onItem(UniOnItemTransformToUni.java:57)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransform$UniOnItemTransformProcessor.onItem(UniOnItemTransform.java:43)
	at io.smallrye.mutiny.operators.uni.UniMemoizeOp.subscribe(UniMemoizeOp.java:66)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransform.subscribe(UniOnItemTransform.java:22)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.operators.uni.UniOnItemTransformToUni.subscribe(UniOnItemTransformToUni.java:25)
	at io.smallrye.mutiny.operators.AbstractUni.subscribe(AbstractUni.java:36)
	at io.smallrye.mutiny.groups.UniSubscribe.withSubscriber(UniSubscribe.java:50)
	at io.smallrye.mutiny.groups.UniSubscribe.with(UniSubscribe.java:90)
	at io.quarkus.vertx.http.runtime.security.HttpAuthorizer.doPermissionCheck(HttpAuthorizer.java:127)
	at io.quarkus.vertx.http.runtime.security.HttpAuthorizer.checkPermission(HttpAuthorizer.java:104)
	at io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder$3.handle(HttpSecurityRecorder.java:227)
	at io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder$3.handle(HttpSecurityRecorder.java:219)
	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1193)
	at io.vertx.ext.web.impl.RoutingContextImplBase.iterateNext(RoutingContextImplBase.java:163)
	at io.vertx.ext.web.impl.RoutingContextImpl.next(RoutingContextImpl.java:141)
	at io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder$2$2.onItem(HttpSecurityRecorder.java:152)
	at io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder$2$2.onItem(HttpSecurityRecorder.java:113)
	at io.smallrye.mutiny.operators.uni.UniMemoizeOp.drain(UniMemoizeOp.java:152)
	at io.smallrye.mutiny.operators.uni.UniMemoizeOp.onItem(UniMemoizeOp.java:172)
	at io.smallrye.mutiny.operators.uni.builders.DefaultUniEmitter.complete(DefaultUniEmitter.java:36)
	at io.quarkus.security.runtime.QuarkusIdentityProviderManagerImpl$1$1$1$1.run(QuarkusIdentityProviderManagerImpl.java:58)
	at io.quarkus.vertx.core.runtime.VertxCoreRecorder$13.runWith(VertxCoreRecorder.java:543)
	at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
	at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
	at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
	at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
	at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
	at java.base/java.lang.Thread.run(Thread.java:833)

[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0, Time elapsed: 33.504 s <<< FAILURE! - in org.acme.getting.started.GreetingResourceTest
[ERROR] org.acme.getting.started.GreetingResourceTest.testHelloEndpoint  Time elapsed: 3.214 s  <<< FAILURE!
java.lang.AssertionError: 
1 expectation failed.
Expected status code <200> but was <500>.

	at org.acme.getting.started.GreetingResourceTest.testHelloEndpoint(GreetingResourceTest.java:20)

2022-02-14 14:45:05,165 INFO  [io.quarkus] (main) Quarkus stopped in 0.094s
[INFO] 
[INFO] Results:
[INFO] 
[ERROR] Failures: 
[ERROR]   GreetingResourceTest.testHelloEndpoint:20 1 expectation failed.
Expected status code <200> but was <500>.

[INFO] 
[ERROR] Tests run: 1, Failures: 1, Errors: 0, Skipped: 0
[INFO] 
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  46.189 s
[INFO] Finished at: 2022-02-14T14:45:05Z
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:3.0.0-M5:test (default-test) on project getting-started: There are test failures.
[ERROR] 
[ERROR] Please refer to /home/lthiebaud/quarkus_request_already_read/target/surefire-reports for the individual test results.
[ERROR] Please refer to dump files (if any exist) [date].dump, [date]-jvmRun[N].dump and [date].dumpstream.
[ERROR] -> [Help 1]
[ERROR] 
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR] 
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException

@antsfiles
Copy link

Hi,
I have the same type of error if the login or pasword is invalid

  • JPA + Form Auth
  • File properties + form auth

And request has not end then. (pending without error for the client in JS)

Note: On Quarkus 2.8.2.

`
22-04-27 18:10:38,587 ERROR [org.jbo.thr.errors] (executor-thread-0) Thread Thread[executor-thread-0,5,main] threw an uncaught exception: java.lang.IllegalStateException: Request has already been read
at io.vertx.core.http.impl.Http2ServerRequest.checkEnded(Http2ServerRequest.java:259)
at io.vertx.core.http.impl.Http2ServerRequest.fetch(Http2ServerRequest.java:310)
at io.vertx.core.http.impl.Http2ServerRequest.resume(Http2ServerRequest.java:304)
at io.quarkus.vertx.http.runtime.ResumingRequestWrapper.resume(ResumingRequestWrapper.java:35)
at io.quarkus.vertx.http.runtime.AbstractRequestWrapper.resume(AbstractRequestWrapper.java:65)
at io.vertx.ext.web.impl.HttpServerRequestWrapper.resume(HttpServerRequestWrapper.java:116)
at io.quarkus.vertx.http.runtime.security.HttpAuthenticator.sendChallenge(HttpAuthenticator.java:137)
at io.quarkus.vertx.http.runtime.security.HttpAuthenticator_Subclass.sendChallenge$$superforward1(Unknown Source)
at io.quarkus.vertx.http.runtime.security.HttpAuthenticator_Subclass$$function$$7.apply(Unknown Source)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.proceed(AroundInvokeInvocationContext.java:54)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.proceed(InvocationInterceptor.java:62)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor.monitor(InvocationInterceptor.java:51)
at io.quarkus.arc.runtime.devconsole.InvocationInterceptor_Bean.intercept(Unknown Source)
at io.quarkus.arc.impl.InterceptorInvocation.invoke(InterceptorInvocation.java:41)
at io.quarkus.arc.impl.AroundInvokeInvocationContext.perform(AroundInvokeInvocationContext.java:41)
at io.quarkus.arc.impl.InvocationContexts.performAroundInvoke(InvocationContexts.java:32)
at io.quarkus.vertx.http.runtime.security.HttpAuthenticator_Subclass.sendChallenge(Unknown Source)
at io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder$2$1.accept(HttpSecurityRecorder.java:81)
at io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder$2$1.accept(HttpSecurityRecorder.java:75)
at io.quarkus.vertx.http.runtime.security.HttpSecurityRecorder$2$2.onFailure(HttpSecurityRecorder.java:162)
at io.smallrye.mutiny.operators.uni.UniMemoizeOp.drain(UniMemoizeOp.java:158)
at io.smallrye.mutiny.operators.uni.UniMemoizeOp.onFailure(UniMemoizeOp.java:190)
at io.smallrye.mutiny.operators.uni.builders.DefaultUniEmitter.fail(DefaultUniEmitter.java:53)
at io.quarkus.vertx.http.runtime.security.FormAuthenticationMechanism$1$1$2.accept(FormAuthenticationMechanism.java:106)
at io.quarkus.vertx.http.runtime.security.FormAuthenticationMechanism$1$1$2.accept(FormAuthenticationMechanism.java:103)
at io.smallrye.context.impl.wrappers.SlowContextualConsumer.accept(SlowContextualConsumer.java:21)
at io.smallrye.mutiny.helpers.UniCallbackSubscriber.onFailure(UniCallbackSubscriber.java:65)
at io.smallrye.mutiny.operators.uni.builders.DefaultUniEmitter.fail(DefaultUniEmitter.java:53)
at io.quarkus.security.runtime.QuarkusIdentityProviderManagerImpl$1$1$1$1.run(QuarkusIdentityProviderManagerImpl.java:60)
at io.quarkus.vertx.core.runtime.VertxCoreRecorder$14.runWith(VertxCoreRecorder.java:548)
at org.jboss.threads.EnhancedQueueExecutor$Task.run(EnhancedQueueExecutor.java:2449)
at org.jboss.threads.EnhancedQueueExecutor$ThreadBody.run(EnhancedQueueExecutor.java:1478)
at org.jboss.threads.DelegatingRunnable.run(DelegatingRunnable.java:29)
at org.jboss.threads.ThreadLocalResettingRunnable.run(ThreadLocalResettingRunnable.java:29)
at io.netty.util.concurrent.FastThreadLocalRunnable.run(FastThreadLocalRunnable.java:30)
at java.base/java.lang.Thread.run(Thread.java:829)

`

@iompo
Copy link

iompo commented Jun 14, 2022

Hi, I have the same problem described by iriikoad with https and wrong password. Reproducer available at https://github.com/iompo/request-already-read

@iompo
Copy link

iompo commented Jun 14, 2022

The error does not happen if i use Uni.createFrom().emitter instead of the context.runBlocking, emitting a fail event instead of throwing the exception.

@antsfiles
Copy link

I just tested Quarkus 2.10.1: still error.

@antsfiles
Copy link

The error does not happen if i use Uni.createFrom().emitter instead of the context.runBlocking, emitting a fail event instead of throwing the exception.

Can you describe how you do this?

ps: Still error with Quarkus 2.11

ava.lang.IllegalStateException: Request has already been read
	at io.vertx.core.http.impl.Http2ServerRequest.checkEnded(Http2ServerRequest.java:263)
	at io.vertx.core.http.impl.Http2ServerRequest.pause(Http2ServerRequest.java:300)
	at io.quarkus.vertx.http.runtime.ResumingRequestWrapper.pause(ResumingRequestWrapper.java:28)
	at io.quarkus.vertx.http.runtime.AbstractRequestWrapper.pause(AbstractRequestWrapper.java:59)
	at io.vertx.ext.web.impl.HttpServerRequestWrapper.pause(HttpServerRequestWrapper.java:114)
	at org.jboss.resteasy.reactive.server.vertx.VertxResteasyReactiveRequestContext.<init>(VertxResteasyReactiveRequestContext.java:79)
	at io.quarkus.resteasy.reactive.server.runtime.QuarkusResteasyReactiveRequestContext.<init>(QuarkusResteasyReactiveRequestContext.java:27)
	at io.quarkus.resteasy.reactive.server.runtime.ResteasyReactiveRecorder$5.createContext(ResteasyReactiveRecorder.java:164)
	at org.jboss.resteasy.reactive.server.handlers.RestInitialHandler.beginProcessing(RestInitialHandler.java:46)
	at org.jboss.resteasy.reactive.server.vertx.ResteasyReactiveVertxHandler.handle(ResteasyReactiveVertxHandler.java:17)
	at org.jboss.resteasy.reactive.server.vertx.ResteasyReactiveVertxHandler.handle(ResteasyReactiveVertxHandler.java:7)
	at io.vertx.ext.web.impl.RouteState.handleContext(RouteState.java:1284)

@iompo
Copy link

iompo commented Sep 2, 2022

First you send a an event on the event bus:

public class DbUserPasswordIdentityProvider implements IdentityProvider<UsernamePasswordAuthenticationRequest> {

    @Inject EventBus eventBus;

    @Override
    public Class<UsernamePasswordAuthenticationRequest> getRequestType() {
        return UsernamePasswordAuthenticationRequest.class;
    }

    @Override
    public Uni<SecurityIdentity> authenticate(UsernamePasswordAuthenticationRequest request, AuthenticationRequestContext context) {
        return eventBus.<AppUser>request(AuthenticationEvents.AUTHENTICATE_CREDENTIALS, request).onItem().transform(this::fromAppUser);
    }

    private SecurityIdentity fromAppUser(Message<AppUser> appUserMessage) {
        return QuarkusSecurityIdentity.builder()
                .addRole("user")
                .setPrincipal(new QuarkusPrincipal(appUserMessage.body().getUsername()))
                .build();
    }
}

And then you handle the authentication request, sending back the required info to create a security identity, or an exception if the credentials are wrong:

@Dependent
public class RequestAuthenticator {

    @Inject
    EntityManagerFactory entityManagerFactory;

    @ConsumeEvent(value = AuthenticationEvents.AUTHENTICATE_CREDENTIALS, blocking = true)
    public AppUser authenticateUserPassword(UsernamePasswordAuthenticationRequest userPasswordRequest) {
        EntityManager entityManager = getReadOnlyEntityManager();
        try {
            return getUserFromUsername(entityManager, userPasswordRequest.getUsername());
        } finally {
            entityManager.close();
        }
    }

    @ConsumeEvent(value = AuthenticationEvents.AUTHENTICATE_TRUSTED, blocking = true)
    public AppUser authenticateTrusted(TrustedAuthenticationRequest trustedRequest) {
        EntityManager entityManager = getReadOnlyEntityManager();
        try {
            return getUserFromUsername(entityManager, trustedRequest.getPrincipal());
        } finally {
            entityManager.close();
        }
    }

    private AppUser getUserFromUsername(EntityManager entityManager, String username) {
        TypedQuery<AppUser> query = entityManager.createQuery("SELECT u from AppUser u where u.username = :username", AppUser.class);
        query.setParameter("username", username);
        List<AppUser> users = query.getResultList();
        if (!users.isEmpty()) {
            return users.get(0);
        } else {
            throw new AuthenticationFailedException("Invalid credentials");
        }
    }

    private EntityManager getReadOnlyEntityManager() {
        EntityManager readOnly = entityManagerFactory.createEntityManager();
        ((Session) readOnly).setHibernateFlushMode(FlushMode.MANUAL);
        ((Session) readOnly).setDefaultReadOnly(true);

        return readOnly;
    }

}

@antsfiles
Copy link

Sorry for the late answer.

I see what you mean, so I tried to use a custom HttpAuthenticationMechanism that calls FormAuthenticationMechanism.

If I throw an AuthenticationFailedException in the function authenticate, I can see the 401 response.
But I can't manage to use the FormAuthenticationMechanism function to throw the AuthenticationFailedException in this function as FormAuthenticationMechanism use an other thread to read the request.

@Alternative
@Priority(1)
@ApplicationScoped
public class CustomFormAuthMechanism implements HttpAuthenticationMechanism {
    @Inject
    FormAuthenticationMechanism delegate;
    @Override
    public Uni<SecurityIdentity> authenticate(RoutingContext context, IdentityProviderManager identityProviderManager) {

      // throw new AuthenticationFailedException()  here will work... but how to use FormAuthenticationMechanism  ?

      Uni<SecurityIdentity> uni= delegate.authenticate(context, identityProviderManager);
       // I do I throw an exception in this function if the form authenticate throw an error???
       return uni;
   }

@antsfiles
Copy link

After debugging, it's in the HttpAuthenticator, method sendChallenge:

public Uni<Boolean> sendChallenge(RoutingContext routingContext) {
routingContext.request().resume(); ///-> this will throw the error

@geoand
Copy link
Contributor

geoand commented Oct 10, 2022

@sberyozkin ^

@antsfiles
Copy link

any news? it's a problem when it uses Http2.

@michalvavrik
Copy link
Member

Hmm, I remember I was already debugging it few months ago and abandon it for some reason. I'll look again and let you know.

@michalvavrik michalvavrik self-assigned this Jan 30, 2023
@antsfiles
Copy link

antsfiles commented Jan 30, 2023

ok.. to avoid this, i re-write the io.quarkus.vertx.http.runtime.security.HttpAuthenticator.DefaultAuthFailureHandler with a 'catch' and give it to the request in the method authenticate:

@Alternative
@Priority(1)
@ApplicationScoped
public class CustomFormAuthMechanism implements HttpAuthenticationMechanism {


@Override
    public Uni<SecurityIdentity> authenticate(RoutingContext context, IdentityProviderManager identityProviderManager) {
        //change the error handler
        context.put(QuarkusHttpUser.AUTH_FAILURE_HANDLER, new DefaultAuthFailureHandler(this));
       ....
    }

    public static final class DefaultAuthFailureHandler implements BiConsumer<RoutingContext, Throwable> {

        CustomFormOrJwtAuthMechanism meca;

        private DefaultAuthFailureHandler(CustomFormOrJwtAuthMechanism m) {
            this.meca = m;
        }

       @Override
        public void accept(RoutingContext event, Throwable throwable) {
            throwable = extractRootCause(throwable);
            // auth failed
            if (throwable instanceof AuthenticationFailedException) {

                // we want to consume any body content if present
                // challenges won't read the body, and if we don't consume
                // things can get stuck
                try {
                    event.request().resume();
                } catch (Exception e) {
                    // may happen in HTTP2: 'Request has already been read'
                }
...

@michalvavrik
Copy link
Member

@iriikoad alright I've done following changes to your reproducer:

  • quarkus-vertx-web -> quarkus-reactive-routes
  • r.post("/test").handler(context -> {}); (that's were it hangs) to r.post("/test").handler(context -> context.end("done"));

and tested the reproducer with 999-SNAPSHOT and 2.16.0.Final and the issue can't be reproduced anymore. Please test it and in case you can reproduce the issue, update reproducer and let me know. Thank you

@michalvavrik michalvavrik added the triage/needs-reproducer We are waiting for a reproducer. label Jan 31, 2023
@antsfiles
Copy link

I updated to 2.16.0.Final, still same issue with same exception.

I use this:

        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-arc</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy-reactive</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-resteasy-reactive-jackson</artifactId>
        </dependency>
        <dependency>
            <groupId>io.quarkus</groupId>
            <artifactId>quarkus-security</artifactId>
        </dependency>

<!-- to simplify logins (dev only) -->
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-elytron-security-properties-file</artifactId>
</dependency>
quarkus.http.auth.form.enabled=true

@michalvavrik
Copy link
Member

ah, sorry @iriikoad I didn't mention you just commented here, not created issue. Can you provide full reproducer - link to github project, please? we have countless tests with configuration that you mentioned that are passing, therefore you can imagine it's not enough information!

@antsfiles
Copy link

I just created a project
https://github.com/iriikoad/quarkus-reproduce-err-timeout
Run mvn quarkus:devand follow the readme.

@michalvavrik
Copy link
Member

@iriikoad thanks for reproducer, it helped

@quarkus-bot quarkus-bot bot added this to the 3.0 - main milestone Feb 14, 2023
iocanel pushed a commit to iocanel/quarkus that referenced this issue Feb 14, 2023
@gsmet gsmet modified the milestones: 3.0 - main, 2.16.3.Final Feb 15, 2023
gsmet pushed a commit to gsmet/quarkus that referenced this issue Feb 15, 2023
benkard added a commit to benkard/mulkcms2 that referenced this issue Apr 2, 2023
This MR contains the following updates:

| Package | Type | Update | Change |
|---|---|---|---|
| [flow-bin](https://github.com/flowtype/flow-bin) ([changelog](https://github.com/facebook/flow/blob/master/Changelog.md)) | devDependencies | minor | [`^0.199.0` -> `^0.200.0`](https://renovatebot.com/diffs/npm/flow-bin/0.199.0/0.200.0) |
| [com.rometools:rome](http://rometools.com) ([source](https://github.com/rometools/rome)) | compile | minor | `1.18.0` -> `1.19.0` |
| [org.postgresql:postgresql](https://jdbc.postgresql.org) ([source](https://github.com/pgjdbc/pgjdbc)) | build | patch | `42.5.3` -> `42.5.4` |
| [org.jsoup:jsoup](https://jsoup.org/) ([source](https://github.com/jhy/jsoup)) | compile | patch | `1.15.3` -> `1.15.4` |
| [io.quarkus:quarkus-maven-plugin](https://github.com/quarkusio/quarkus) | build | patch | `2.16.2.Final` -> `2.16.3.Final` |
| [io.quarkus:quarkus-universe-bom](https://github.com/quarkusio/quarkus-platform) | import | patch | `2.16.2.Final` -> `2.16.3.Final` |

---

### Release Notes

<details>
<summary>flowtype/flow-bin</summary>

### [`v0.200.0`](flow/flow-bin@9618443...b6c1eb0)

[Compare Source](flow/flow-bin@9618443...b6c1eb0)

### [`v0.199.1`](flow/flow-bin@05bb4e3...9618443)

[Compare Source](flow/flow-bin@05bb4e3...9618443)

</details>

<details>
<summary>rometools/rome</summary>

### [`v1.19.0`](https://github.com/rometools/rome/releases/tag/1.19.0)

[Compare Source](rometools/rome@1.18.0...1.19.0)

<!-- Release notes generated using configuration in .github/release.yml at 1.19.0 -->

#### What's Changed

##### 🔨 Dependency Upgrades

-   Bump flatten-maven-plugin from 1.2.7 to 1.3.0 by [@&#8203;dependabot](https://github.com/dependabot) in rometools/rome#565
-   Bump maven-bundle-plugin from 5.1.5 to 5.1.8 by [@&#8203;dependabot](https://github.com/dependabot) in rometools/rome#563
-   Bump maven-dependency-plugin from 3.3.0 to 3.5.0 by [@&#8203;dependabot](https://github.com/dependabot) in rometools/rome#602
-   Bump maven-deploy-plugin from 2.8.2 to 3.1.0 by [@&#8203;dependabot](https://github.com/dependabot) in rometools/rome#607
-   Bump maven-jar-plugin from 3.2.2 to 3.3.0 by [@&#8203;dependabot](https://github.com/dependabot) in rometools/rome#574
-   Bump maven-javadoc-plugin from 3.3.1 to 3.5.0 by [@&#8203;dependabot](https://github.com/dependabot) in rometools/rome#609
-   Bump maven-scm-plugin from 1.12.2 to 1.13.0 by [@&#8203;dependabot](https://github.com/dependabot) in rometools/rome#554
-   Bump assertj-core from 3.22.0 to 3.24.2 by [@&#8203;dependabot](https://github.com/dependabot) in rometools/rome#603
-   Bump slf4j-api from 1.7.36 to 2.0.6 by [@&#8203;dependabot](https://github.com/dependabot) in rometools/rome#596

##### Other Changes

-   Bump actions/setup-java from 3.3.0 to 3.10.0 by [@&#8203;dependabot](https://github.com/dependabot) in rometools/rome#606
-   Bump logback-classic from 1.2.10 to 1.3.5 by [@&#8203;PatrickGotthard](https://github.com/PatrickGotthard) in rometools/rome#611

**Full Changelog**: rometools/rome@1.18.0...1.19.0

</details>

<details>
<summary>pgjdbc/pgjdbc</summary>

### [`v42.5.4`](https://github.com/pgjdbc/pgjdbc/blob/HEAD/CHANGELOG.md#&#8203;4254-2023-02-15-102104--0500)

##### Fixed

fix: fix testGetSQLTypeQueryCache by searching for xid type. We used to search for box type but it is now cached. xid is not cached, this nuance is required for the test.
fix OidValueCorrectnessTest BOX_ARRAY OID, by adding BOX_ARRAY to the oidTypeName map \[MR [#&#8203;2810](https://github.com/pgjdbc/pgjdbc/issues/2810)]\((https://github.com/pgjdbc/pgjdbc/pull/2810).
fixes [Issue #&#8203;2804](pgjdbc/pgjdbc#2804).
fix: Make sure that github CI runs tests on all [MRs #&#8203;2809](\(https://github.com/pgjdbc/pgjdbc/pull/2809\)).

</details>

<details>
<summary>quarkusio/quarkus</summary>

### [`v2.16.3.Final`](https://github.com/quarkusio/quarkus/releases/tag/2.16.3.Final)

[Compare Source](quarkusio/quarkus@2.16.2.Final...2.16.3.Final)

##### Major changes

-   [#&#8203;29756](quarkusio/quarkus#29756) - Support custom Flyway credentials/URL

##### Complete changelog

-   [#&#8203;31141](quarkusio/quarkus#31141) - Resolve roles allowed configuration expression after config setup is completed
-   [#&#8203;31129](quarkusio/quarkus#31129) - Fix stuck HTTP2 request when sent challenge has resumed request
-   [#&#8203;31125](quarkusio/quarkus#31125) - Add "keep-alive-enabled" parameter to REST client reactive
-   [#&#8203;31112](quarkusio/quarkus#31112) - Qute - fix assignability check when validating expressions
-   [#&#8203;31099](quarkusio/quarkus#31099) - Use the effective Maven project build config when initializing sources and classes paths for dev mode
-   [#&#8203;31092](quarkusio/quarkus#31092) - Make sure quarkus:go-offline properly supports test scoped dependencies
-   [#&#8203;31077](quarkusio/quarkus#31077) - Qute: regression in template extension method with byte array
-   [#&#8203;31076](quarkusio/quarkus#31076) - Quarkiverse: Install instead of verify
-   [#&#8203;31074](quarkusio/quarkus#31074) - Added quarkus-jms-spi to quarkus bom
-   [#&#8203;31059](quarkusio/quarkus#31059) - Path lookup must also consider interfaces
-   [#&#8203;31046](quarkusio/quarkus#31046) - Simplify Quarkiverse release.yml workflow
-   [#&#8203;31038](quarkusio/quarkus#31038) - Update Instrumentation Processor check logic to match comment
-   [#&#8203;31036](quarkusio/quarkus#31036) - Use CDI when accessing UserTransaction/TransactionManager in QuarkusTransaction
-   [#&#8203;31028](quarkusio/quarkus#31028) - Fix typo in snapstart enable config
-   [#&#8203;31016](quarkusio/quarkus#31016) - Re-initialize platform dependent netty classes/values at runtime
-   [#&#8203;30988](quarkusio/quarkus#30988) - Race condition in SmallRye Config property expansion for [@&#8203;RolesAllowed](https://github.com/RolesAllowed) value?
-   [#&#8203;30964](quarkusio/quarkus#30964) - Add ConfigMappings from a builder class to support full hot reload
-   [#&#8203;30961](quarkusio/quarkus#30961) - Error of quarkus:dev when the project.build.directory is overridden by a profile
-   [#&#8203;30960](quarkusio/quarkus#30960) - Register CDI Bean when ConfigMapping is marked as Unremovable
-   [#&#8203;30922](quarkusio/quarkus#30922) - Fix dependency parsing in JBangBuilderImpl
-   [#&#8203;30885](quarkusio/quarkus#30885) - Add concurrency configuration to the GitHub Action workflows
-   [#&#8203;30843](quarkusio/quarkus#30843) - Micrometer-Extension writes wrong URI-Tag when Path-Variables defined at Interface-Level
-   [#&#8203;30672](quarkusio/quarkus#30672) - Avoid creating CSRF cookie if no CSRF token was created
-   [#&#8203;30648](quarkusio/quarkus#30648) - Support passing filename to multipart form data output
-   [#&#8203;30594](quarkusio/quarkus#30594) - CSRF: exception thrown when authentication falied
-   [#&#8203;30570](quarkusio/quarkus#30570) - Set filename for PartItems in MultipartFormDataOutput
-   [#&#8203;30455](quarkusio/quarkus#30455) - Introduce `quarkus.datasource.devservices.init-script-path`
-   [#&#8203;29756](quarkusio/quarkus#29756) - Support custom Flyway credentials/URL
-   [#&#8203;29631](quarkusio/quarkus#29631) - [@&#8203;Unremovable](https://github.com/Unremovable) ConfigMapping is still removed
-   [#&#8203;29630](quarkusio/quarkus#29630) - Changes to configmappings not being applied during hot reload
-   [#&#8203;28709](quarkusio/quarkus#28709) - QuarkusTransaction does not fire [@&#8203;Initialized](https://github.com/Initialized)(TransactionScoped.class)
-   [#&#8203;24639](quarkusio/quarkus#24639) - configure dedicated db user for database migrations: DML-only user for datasource, but DDL user for migration
-   [#&#8203;23360](quarkusio/quarkus#23360) - "Request has already been read" using vertx + auth
-   [#&#8203;17839](quarkusio/quarkus#17839) - Invalid memory configuration for netty maxDirectMemory in native image

</details>

<details>
<summary>quarkusio/quarkus-platform</summary>

### [`v2.16.3.Final`](quarkusio/quarkus-platform@2.16.2.Final...2.16.3.Final)

[Compare Source](quarkusio/quarkus-platform@2.16.2.Final...2.16.3.Final)

</details>

---

### Configuration

📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - At any time (no schedule defined).

🚦 **Automerge**: Enabled.

♻ **Rebasing**: Whenever MR is behind base branch, or you tick the rebase/retry checkbox.

👻 **Immortal**: This MR will be recreated if closed unmerged. Get [config help](https://github.com/renovatebot/renovate/discussions) if that's undesired.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this MR, check this box

---

This MR has been generated by [Renovate Bot](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiIzNC4yNC4wIiwidXBkYXRlZEluVmVyIjoiMzQuMjQuMCJ9-->
@gsmet gsmet modified the milestones: 2.16.3.Final, 2.13.8.Final May 9, 2023
gsmet pushed a commit to gsmet/quarkus that referenced this issue May 9, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/security kind/bug Something isn't working
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants