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

RESTEASY003765: Response is closed #1771

Open
niallrox opened this issue Feb 23, 2024 · 4 comments
Open

RESTEASY003765: Response is closed #1771

niallrox opened this issue Feb 23, 2024 · 4 comments
Labels

Comments

@niallrox
Copy link

niallrox commented Feb 23, 2024

Hello.

Exception that response is already closed is thrown, while involve logbook into keycloak admin client.

Steps to reproduce.

Using
SB3
and

    implementation("org.keycloak:keycloak-admin-client:23.0.3")
    implementation("org.zalando:logbook-spring-boot-starter:3.7.2")
    implementation("org.zalando:logbook-jaxrs:3.7.2")

Bean with client

    @Bean
    fun surdoRealm(
        keycloakProperties: KeycloakProperties,
        resteasyClient: ResteasyClient
    ): RealmResource {
        val keycloak = KeycloakBuilder.builder()
            .serverUrl(keycloakProperties.host)
            .realm(keycloakProperties.realm)
            .grantType(OAuth2Constants.CLIENT_CREDENTIALS)
            .clientId(keycloakProperties.clientId)
            .clientSecret(keycloakProperties.clientSecret)
            .resteasyClient(resteasyClient)
            .build()

        return keycloak.realm(keycloakProperties.realm)
    }

    @Bean
    fun loggingClient(logbook: Logbook): ResteasyClient {
        val clientBuilder = ClientBuilderWrapper.create(SSLContext.getDefault(), false) as ResteasyClientBuilder
        clientBuilder.register(JacksonProvider::class.java, JACKSON_PROVIDER_PRIORITY)
        val client = clientBuilder.build()
        client.register(LogbookClientFilter(logbook))
        return client
    }

application.yml

logbook:
  predicate:
    include:
      - path: /**
    exclude:
      - path: /actuator/health
      - path: /internal/**
  filter.enabled: true
  secure-filter.enabled: true
  format.style: http
  strategy: body-only-if-status-at-least
  obfuscate:
    headers:
      - Authorization
      - X-Secret
    parameters:
      - access_token
      - password
  write:
    chunk-size: 1000
  attribute-extractors:
    - type: JwtFirstMatchingClaimExtractor
      claim-names: [ "sub", "subject" ]
      claim-key: Principal
    - type: JwtAllMatchingClaimsExtractor
      claim-names: [ "sub", "iat" ]

This is the log

2024-02-23 14:10:43,554 ?[39mTRACE?[0;39m [?[34mTest worker?[0;39m] [] ?[33morg.zalando.logbook.core.DefaultHttpLogWriter?[0;39m: Outgoing Request: 80c7b39f63628838
Remote: localhost
POST http://localhost:57696/realms/master/protocol/openid-connect/token HTTP/1.1
Accept: application/json
Content-Type: application/x-www-form-urlencoded

grant_type=password&username=admin&password=XXX&client_id=admin-cli
2024-02-23 14:10:43,589 ?[39mTRACE?[0;39m [?[34mTest worker?[0;39m] [] ?[33morg.zalando.logbook.core.DefaultHttpLogWriter?[0;39m: Incoming Response: 80c7b39f63628838
Duration: 35 ms
HTTP/1.1 200 OK
Cache-Control: no-store
content-length: 1822
Content-Type: application/json
Pragma: no-cache
Referrer-Policy: no-referrer
Set-Cookie: KEYCLOAK_LOCALE=; Version=1; Comment=Expiring cookie; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Max-Age=0; Path=/realms/master/; HttpOnly, KC_RESTART=; Version=1; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Max-Age=0; Path=/realms/master/; HttpOnly, KC_AUTH_STATE=; Version=1; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Max-Age=0; Path=/realms/master/
Strict-Transport-Security: max-age=31536000; includeSubDomains
X-Content-Type-Options: nosniff
X-Frame-Options: SAMEORIGIN
X-XSS-Protection: 1; mode=block

{"access_token":"XXX","expires_in":60,"refresh_expires_in":1800,"refresh_token":"XXX","token_type":"Bearer","not-before-policy":0,"session_state":"f6dc8be8-52a1-448f-8042-5f6b777eca74","scope":"profile email"}

And the error
jakarta.ws.rs.client.ResponseProcessingException: java.lang.IllegalStateException: RESTEASY003765: Response is closed.

I think after logbook read and log the response, client can't parse it, because you can't read response more than once. However, I haven't found another solution or sink implementation which could provide me that opportunity.
Thanks in advance.

@niallrox niallrox added the Bug label Feb 23, 2024
@lukasniemeier-zalando
Copy link
Member

@niallrox would you be able to provide a small Github repository that showcases the problem (i.e. your classes and configuration from above)?

@niallrox
Copy link
Author

niallrox commented May 29, 2024

Unfortunately, I can't share the whole repository, it's private. However, I will create a small repo that reproduces the same issue and easy to run. I'll do it approximately in 2 days.

niallrox added a commit to niallrox/keycloak-logbook that referenced this issue Jun 3, 2024
@niallrox
Copy link
Author

niallrox commented Jun 3, 2024

@de-winter
Copy link

Hey,

i recently tried to integrate Logbook in our Quarkus applications and observed a similar behavior.
Logging Container Request/Responses and Client Requests work fine, Client responses are logged, are however followed by said error...

I also provided a repository showcasing the error:
https://github.com/de-winter/logbook-client-response-error-example

Quarkus (with RESTEasy) 3.11
Logbook 3.9

Test execution:


2024-06-24 15:07:38,142 TRACE [org.zal.log.Logbook] (main) Outgoing Request: d4bf46af15ac4c98
Remote: localhost
POST http://localhost:8081/hello HTTP/1.1
Accept: text/plain
Content-Type: application/json

World
2024-06-24 15:07:38,153 TRACE [org.zal.log.Logbook] (executor-thread-1) Incoming Request: dea912a673fcc338
Remote: localhost:8081
POST http://localhost:8081/hello HTTP/1.1
Accept: text/plain
Connection: Keep-Alive
Content-Length: 5
Content-Type: application/json
Host: localhost:8081
User-Agent: Apache-HttpClient/4.5.14 (Java/17.0.6)

World
2024-06-24 15:07:38,154 TRACE [org.zal.log.Logbook] (executor-thread-1) Outgoing Response: dea912a673fcc338
Duration: 1 ms
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8

Hello World
2024-06-24 15:07:38,158 TRACE [org.zal.log.Logbook] (main) Incoming Response: d4bf46af15ac4c98
Duration: 21 ms
HTTP/1.1 200 OK
content-length: 11
Content-Type: text/plain;charset=UTF-8

Hello World

jakarta.ws.rs.ProcessingException: RESTEASY004640: Stream is closed

	at org.jboss.resteasy.client.jaxrs.internal.ClientResponse.getEntityStream(ClientResponse.java:144)
	at org.jboss.resteasy.client.jaxrs.internal.ClientResponseContextImpl.getEntityStream(ClientResponseContextImpl.java:128)
	at org.jboss.resteasy.microprofile.client.PartialResponse.<init>(PartialResponse.java:52)
	at org.jboss.resteasy.microprofile.client.ExceptionMapping.filter(ExceptionMapping.java:86)
	at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.filterResponse(ClientInvocation.java:667)
	at org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke(ClientInvocation.java:428)
	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invokeSync(ClientInvoker.java:134)
	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientInvoker.invoke(ClientInvoker.java:103)
	at org.jboss.resteasy.client.jaxrs.internal.proxy.ClientProxy.invoke(ClientProxy.java:61)
	at jdk.proxy5/jdk.proxy5.$Proxy71.hello(Unknown Source)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at io.quarkus.restclient.runtime.QuarkusProxyInvocationHandler.invoke(QuarkusProxyInvocationHandler.java:165)
	at jdk.proxy5/jdk.proxy5.$Proxy74.hello(Unknown Source)
	at example.logbook.ExampleTest.testHelloClient(ExampleTest.java:30)
	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
	at io.quarkus.test.junit.QuarkusTestExtension.runExtensionMethod(QuarkusTestExtension.java:1017)
	at io.quarkus.test.junit.QuarkusTestExtension.interceptTestMethod(QuarkusTestExtension.java:831)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)
	at java.base/java.util.ArrayList.forEach(ArrayList.java:1511)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

3 participants