Ensure consistent transaction rollback across all error response paths#50943
Conversation
|
Looks promising @mabartos |
acd82f7 to
ea6dccf
Compare
There was a problem hiding this comment.
Pull request overview
Ensures Keycloak error helpers consistently roll back request transactions while preserving selected security-related side effects in independent transactions.
Changes:
- Centralizes rollback behavior for error pages and exceptions.
- Adds fresh-session lookup and transaction utilities.
- Moves session invalidation and permission-ticket persistence into separate transactions.
Reviewed changes
Copilot reviewed 13 out of 13 changed files in this pull request and generated 2 comments.
Show a summary per file
| File | Description |
|---|---|
services/.../AsyncResponseTransaction.java |
Preserves error responses after rollback. |
services/.../RollbackWebApplicationException.java |
Adds rollback-aware exception base. |
services/.../ErrorResponseException.java |
Uses the rollback-aware base. |
services/.../ErrorPageException.java |
Uses centralized rollback handling. |
services/.../ErrorPage.java |
Marks error-page transactions rollback-only. |
services/.../CorsErrorResponseException.java |
Rolls back CORS error paths. |
services/.../TokenManager.java |
Persists session invalidation separately. |
services/.../AbstractRefreshTokenProvider.java |
Persists client-session detachment. |
services/.../ResourceOwnerPasswordCredentialsGrantType.java |
Separately removes authentication sessions. |
services/.../AuthorizationCodeGrantType.java |
Separately invalidates reused-code sessions. |
server-spi-private/.../SessionLookup.java |
Adds fresh-session entity lookups. |
server-spi-private/.../KeycloakModelUtils.java |
Adds independent transaction helper. |
server-spi-private/.../PermissionTicketAwareDecisionResultCollector.java |
Persists denied-request tickets separately. |
|
@mabartos have there been inconsistencies for a while? Looking at the current undertow logic, which seems to be what was used in Wildfly as well, on any uncaught exception the transaction would be rolled back - That would have rolled back anything that throw any WebApplicationException regardless of whether it contained a Response. If I understand correctly the current state is that WebApplicationExceptions thrown containing a Response, will not roll back the transaction. So the changes here attempt to make it more like it used to be - any RollbackWebApplicationException or exception handled by the KeycloakErrorHandler will cause the transaction to be rolled back. Are there some WebApplicationExceptions thrown where we don't expect a rollback? Or do we need to make sure that all the WebApplicationException we throw use RollbackWebApplicationException as the base class?
Ideally we should avoid the paradigm of suspending and starting a new transaction. Is it possible that this could be handled as an enlistAfterCompletion transaction in the rollback method? |
|
@shawkins Thanks for the review!
Yes, we detected the behavior in the #50850, so there might be more cases where it can provide such a security issue - IMO, that's why we need to make it more robust.
Yes, exactly. Our KeycloakErrorHandler is not called when the WebApplicationException contains a response; otherwise the rollback is set for every error on KC side.
Yes, we attempt to cover all error cases and always set TX rollback.
I did an analysis, and there should not be any, where we explicitly expect a commit of the main transaction. There are some places, where we need to store soma data along the way - brute force detector, error events, UMA, session invalidations. It'd be good if any new KC WAE exception would extend the
Yes, that might be a more suitable approach. I'll look into it. Thanks! |
Closes keycloak#50911 Signed-off-by: Martin Bartoš <mabartos@redhat.com>
Unreported flaky test detectedIf the flaky tests below are affected by the changes, please review and update the changes accordingly. Otherwise, a maintainer should report the flaky tests prior to merging the PR. org.keycloak.testsuite.adapter.servlet.SAMLServletAdapterTest#salesMetadataTestKeycloak CI - Adapter IT Strict Cookies org.keycloak.testsuite.adapter.servlet.SAMLServletAdapterTest#employeeSigPostNoIdpKeyTestNoKeyNameInKeyInfoKeycloak CI - Adapter IT Strict Cookies org.keycloak.testsuite.adapter.servlet.SAMLServletAdapterTest#salesPostEncTestKeycloak CI - Adapter IT Strict Cookies |
|
@shawkins Should be ready for review. Thanks! |
shawkins
left a comment
There was a problem hiding this comment.
Maybe we could fill an issue on the RESTEasy side to always execute exception mappers even for the WAE with response.
That feels more like a sure thing. Otherwise the only other thought is whether our CloseSessionFilter could handle the detection of this situation - some way to see if the context has been aborted for example.
Otherwise, everything looks good. Thanks @mabartos
@shawkins Thanks! I'll create an issue on their side. I thought about the CloseSessionFilter as well, but for now, I just chose to have an approach with more freedom (the Rollback WAE can help you but if you need to do some special stuff...) to not break existing deployments in the community. Maybe we can revisit later if we find some more problems. |
|
@shawkins Some additional context: It seems we're quite tied up, as the behavior does not come from the RESTEasy, but rather from the JAX-RS spec: "If the response property of the exception does not contain an entity and an exception mapping provider is available for WebApplicationException or the corresponding subclass, an implementation MUST use the provider to create a new Response instance, otherwise the response property is used directly." https://jakarta.ee/specifications/restful-ws/3.0/jakarta-restful-ws-spec-3.0.html#method_exc So, we cannot break the compliance on the RESTEasy side, and probably not worth to go over the JAX-RS spec itself. |
rmartinc
left a comment
There was a problem hiding this comment.
Thanks @mabartos for the PR and @shawkins for the review! I think this behavior is more aligned with the idea of throwing exception means rollback. We can only trust on tests to see if there are some required changes that now are missing. So we will need to be aware of new issues triggered by this change. But we have time to detect any issue until 26.8. Approving.
Uh oh!
There was an error while loading. Please reload this page.