[keycloak-dev] Authenticator SPI: correct way to recover from JPA PersistenceException

Gary Schulte gary.schulte at opengov.com
Thu Aug 23 14:54:18 EDT 2018


Keycloak 4.1, standalone-ha, postgres db:

As a part of our migration to keycloak, we have a custom authenticator we
are using for the direct grant flow which will "lazily create" users.

If we fail to find the user in local storage, we create the user with
session data from a legacy IDP.  This works well, except in the rare case
where multiple services are authenticating a user for the first time, we
end up with a race condition that yields a ModelDuplicateException:

[0m [31m17:31:41,417 ERROR
[org.keycloak.services.error.KeycloakErrorHandler] (default task-8)
Uncaught server error: org.keycloak.models.ModelDuplicateException:
javax.persistence.PersistenceException:
org.hibernate.exception.ConstraintViolationException: could not execute
statement
at
org.keycloak.connections.jpa.PersistenceExceptionConverter.convert(PersistenceExceptionConverter.java:57)
at
org.keycloak.connections.jpa.PersistenceExceptionConverter.invoke(PersistenceExceptionConverter.java:51)
at com.sun.proxy.$Proxy79.flush(Unknown Source)
at org.keycloak.models.jpa.JpaUserProvider.addUser(JpaUserProvider.java:94)
at
com.opengov.auth.keycloak.delphius.DelphiusAuthenticator.authenticate(DelphiusAuthenticator.java:123)
at
org.keycloak.authentication.DefaultAuthenticationFlow.processFlow(DefaultAuthenticationFlow.java:221)
at
org.keycloak.authentication.AuthenticationProcessor.authenticateOnly(AuthenticationProcessor.java:910)
at
org.keycloak.protocol.oidc.endpoints.TokenEndpoint.resourceOwnerPasswordCredentialsGrant(TokenEndpoint.java:547)
at
org.keycloak.protocol.oidc.endpoints.TokenEndpoint.processGrantRequest(TokenEndpoint.java:184)
...


Ideally we could avoid a 500 response and have the race 'loser' look up the
newly created user, but the session's transaction gets marked rollback, and
further lookup/sql operations fail.

I am not finding a way to flush or restart the transaction state in the
Provider.

I have implemented a failureChallenge that is essentially a 302 redirect
back to the same token endpoint, but there are circumstances where a
redirect loop occurs.  I can sort out and handle these cases, but it feels
a bit crufty.

Is there a better/prescribed way to recover from JPA session errors in a
custom Authenticator?

TIA

Gary S


More information about the keycloak-dev mailing list