Replies: 2 comments 14 replies
-
|
Hi @sguilhen, looking at the code option 2 seems to be the smallest change. Looking a bit more closer at the implementation I did for LDAP, it is strange that the code in the storage provider already decides if a new transaction should be created or an existing should be used, and some other code would decide if it should be enlisted. Also, that other code would decide if it would be enlist() or enlistAfterCompletion(). Therefore I would propose the following change: the one who creates the transaction should also enlist it with the session, in this case the one who calls factory.createTransaction() would then also enlist it with the session. WDYT? |
Beta Was this translation helpful? Give feedback.
-
|
Attached is the diagram of the setup that we agreed on in the call:
|
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
I've finished the implementation of the user login failures JPA storage and while testing it I came across this error in tests that remove more than one user via
UserManager:UserSessionProviderTest is a good example of a test that causes this error. Basically this is what happens:
UserManager.removeUserto remove more than one user as part of the same transaction.UserRemovedEventis generated and is handled by the MapUserLoginFailureProviderFactory.MapUserLoginFailureProvider, which on creation callsstore.createTransaction(session).jpa-map-tx-modelType.hashCode, returning the previoustxif one is found in the session or creating a newtxotherwise.So when removing the first user, a new transaction is created for the user login failure and enlisted. From that point on, every time the
MapUserLoginFailureProviderFactoryhandles the removal event, it creates aMapUserLoginFailureProviderthat in turn fetches the previously createdtxfrom the session and enlists it again.When the overall transaction is committed, the user login failure transaction is committed multiple times because it has been enlisted more than once while handling the user removal event, which causes the exception described above.
I could think of a few ways to get around it:
removeUseris called multiple times in the sameUserManageronly by the tests. Our endpoints offer no bulk user removal, so it always processes one removal per transaction. That means we can probably adjust the tests to, for example, remove the created users calling the endpoint directly for each user (adminClient.realm("test").users().get(userId1).remove();), but this requires keeping track o the ids of the users created in each test.enlistmethods inDefaultKeycloakTransactionManagercheck if the same instance has already been enlisted - this would prevent multiplecommit()calls to the same transaction object.MapUserLoginFailureProvider's constructor so that it somehow checks if thetxalready exists in the session before callingenlistAfterComplete. This would ensure that only the provider that created the transaction that is currently active in the session gets to enlist it.I'm currently leaning towards option 2 and make the
enlistmethods check if the list of transactions already contain the transaction being enlisted to avoid enlisting it twice. Option 1 works but will require many changes to all the tests that remove users. Option 3 is feasible although I would need to investigate a viable option for looking up the session because the key is constructed by theJpaMapStorageProviderand is not available to the user login failure provider.Beta Was this translation helpful? Give feedback.
All reactions