I have a Keycloak auth server running in a standalone mode. My requirement is that users should be able to log in with their Google accounts, therefore I added Google IdP following steps in the Keycloak documentation. Once a new user has successfully logged in with their Google account, the new account should be created and stored in the Postgresql DB. To achieve this I created custom user storage provider following this example. The sample covers only the fetch user details part. To support adding new users, I implement addUser
method of org.keycloak.storage.user.UserRegistrationProvider
interface:
@Override
public UserModel addUser(RealmModel realmModel, String s) {
logger.info("create user with username: " + s);
UserEntity userEntity = new UserEntity(s, null, s, s);
em.persist(userEntity);
em.flush();
return new UserAdapter(kcSession, realmModel, model, userEntity);
}
While testing the flow, the Keycloak throws an exception while executing getUserById
custom provider method. According to the logs this method is called multiple times. The method looks like this:
@Override
public UserModel getUserById(String id, RealmModel realm) { logger.info("getUserById: " + id); String persistenceId = StorageId.externalId(id); System.out.println("!!! :" + StorageId.keycloakId(model, id));
System.out.println("!!! " + persistenceId);
Query query = em.createNativeQuery(UserStoreQueries.GET_USER_BY_ID);
query.setParameter(1, Long.valueOf(persistenceId));
Object[] result = (Object[]) query.getSingleResult();
if (result == null) {
logger.info("Could not find user by id: " + id);
return null;
}
return new UserAdapter(kcSession, realm, model, prepareUserEntity(result));
}
Before fetching user from DB, the method tries to extract the user Id (which user table primary key) from the composed Keycloak ID key and use it to get user details. The thing is that at the last method call, the extracted ID value is become equal to NULL somehow, however in the previous method calls it wasn’t, see below:
14:55:05,276 INFO [com.redhat.custom.storage.user.CustomUserStorageProvider] (default task-1) getUserByEmail: kris@gmail.com
14:55:05,328 INFO [com.redhat.custom.storage.user.CustomUserStorageProvider] (default task-1) Could not find user by email: kris@gmail.com
14:55:05,336 INFO [com.redhat.custom.storage.user.CustomUserStorageProvider] (default task-1) getUserByUsername: kris@gmail.com
14:55:05,342 INFO [com.redhat.custom.storage.user.CustomUserStorageProvider] (default task-1) Could not find user by username: kris@gmail.com
14:55:05,343 INFO [com.redhat.custom.storage.user.CustomUserStorageProvider] (default task-1) create user with username: kris@gmail.com
14:55:05,519 INFO [com.redhat.custom.storage.user.CustomUserStorageProvider] (default task-1) getUserById: f:1b171a2b-0d7f-42eb-9c93-89fd7c71347b:9
14:55:05,519 INFO [stdout] (default task-1) !!! :f:1b171a2b-0d7f-42eb-9c93-89fd7c71347b:f:1b171a2b-0d7f-42eb-9c93-89fd7c71347b:9
14:55:05,520 INFO [stdout] (default task-1) !!! 9
14:55:05,563 INFO [com.redhat.custom.storage.user.CustomUserStorageProvider] (default task-1) getUserById: f:1b171a2b-0d7f-42eb-9c93-89fd7c71347b:9
14:55:05,563 INFO [stdout] (default task-1) !!! :f:1b171a2b-0d7f-42eb-9c93-89fd7c71347b:f:1b171a2b-0d7f-42eb-9c93-89fd7c71347b:9
14:55:05,564 INFO [stdout] (default task-1) !!! 9
14:55:05,718 INFO [com.redhat.custom.storage.user.CustomUserStorageProvider] (default task-1) getUserById: f:1b171a2b-0d7f-42eb-9c93-89fd7c71347b:null
14:55:05,719 INFO [stdout] (default task-1) !!! :f:1b171a2b-0d7f-42eb-9c93-89fd7c71347b:f:1b171a2b-0d7f-42eb-9c93-89fd7c71347b:null
14:55:05,719 INFO [stdout] (default task-1) !!! null
14:55:05,720 ERROR [org.jboss.as.ejb3.invocation] (default task-1) WFLYEJB0034: Jakarta Enterprise Beans Invocation failed on component CustomUserStorageProvider for method public default org.keycloak.models.UserModel org.keycloak.storage.user.UserLookupProvider.getUserById(org.keycloak.models.RealmModel,java.lang.String): javax.ejb.EJBTransactionRolledbackException: For input string: "null"
at org.jboss.as.ejb3@23.0.2.Final//org.jboss.as.ejb3.tx.CMTTxInterceptor.invokeInCallerTx(CMTTxInterceptor.java:219)
at org.jboss.as.ejb3@23.0.2.Final//org.jboss.as.ejb3.tx.CMTTxInterceptor.required(CMTTxInterceptor.java:392)
at org.jboss.as.ejb3@23.0.2.Final//org.jboss.as.ejb3.tx.CMTTxInterceptor.processInvocation(CMTTxInterceptor.java:160)
at org.jboss.invocation@1.6.0.Final//org.jboss.invocation.InterceptorContext.proceed(InterceptorContext.java:422)
at org.jboss.invocation@1.6.0.Final//org.jboss.invocation.InterceptorContext$Invocation.proceed(InterceptorContext.java:509)
at org.jboss.weld.core@3.1.6.Final//org.jboss.weld.module.ejb.AbstractEJBRequestScopeActivationInterceptor.aroundInvoke(AbstractEJBRequestScopeActivationInterceptor.java:81)
I am stuck with this. Appreciate, if someone can explain me why my user table PK ID value is removed from the Keycloak composite key?