'Embedded Keycloak springboot application, upgrading keycloak from 12 to 14

Hello I have an SpringBoot application with embedded Keyclock created using the below example https://www.baeldung.com/keycloak-embedded-in-spring-boot-app

I am trying to upgrade Keycloak from 12 to 14 and also upgraded resteasy to 3.15.1.Final, infinispan to 11.0.9.Final. The application fails to start and there is not much in the logs except for a NullPointerException. I am trying to see if any one tried the same and has any suggestions as there are not much in logs. Thanks

2021-07-07 10:02:05 [main] INFO  org.keycloak.services - KC-SERVICES0050: Initializing master realm
2021-07-07 10:02:07 [main] DEBUG org.keycloak.keys.GeneratedRsaKeyProviderFactory - Generated keys for master
2021-07-07 10:02:07 [main] DEBUG org.keycloak.keys.GeneratedHmacKeyProviderFactory - Generated secret for master
2021-07-07 10:02:07 [main] DEBUG org.keycloak.keys.GeneratedAesKeyProviderFactory - Generated secret for master
2021-07-07 10:02:07 [main] DEBUG org.keycloak.connections.jpa.updater.liquibase.lock.LiquibaseDBLockProvider - Going to release database lock namespace=KEYCLOAK_BOOT
2021-07-07 10:02:07 [main] DEBUG org.keycloak.connections.jpa.updater.liquibase.lock.CustomLockService - Going to release database lock
2021-07-07 10:02:07 [main] DEBUG org.keycloak.models.cache.infinispan.InfinispanUserCacheProviderFactory - Registered cluster listeners
2021-07-07 10:02:07 [main] DEBUG org.keycloak.executors.DefaultExecutorsProviderFactory - We are in managed environment. Executor 'java:jboss/ee/concurrency/executor/default' was available.
2021-07-07 10:02:07 [main] DEBUG org.keycloak.executors.DefaultExecutorsProviderFactory - Found executor for 'storage-provider-threads' under JNDI name 'java:jboss/ee/concurrency/executor/storage-provider-threads'
2021-07-07 10:02:07 [main] FATAL org.keycloak.services - java.lang.NullPointerException

2021-07-07 10:02:07 [main] DEBUG org.keycloak.executors.DefaultExecutorsProviderFactory - Found executor for 'storage-provider-threads' under JNDI name 'java:jboss/ee/concurrency/executor/storage-provider-threads'
$$$$$$$$$$$$$$$$Stachtrace$$$$$$$$$$$$$ : java.lang.NullPointerException
    at java.base/java.util.concurrent.ConcurrentHashMap.putVal(ConcurrentHashMap.java:1011)
    at java.base/java.util.concurrent.ConcurrentHashMap.put(ConcurrentHashMap.java:1006)
    at org.keycloak.executors.DefaultExecutorsProviderFactory.getExecutor(DefaultExecutorsProviderFactory.java:113)
    at org.keycloak.executors.DefaultExecutorsProviderFactory$1.getExecutor(DefaultExecutorsProviderFactory.java:68)
    at org.keycloak.utils.ServicesUtils.timeBoundOne(ServicesUtils.java:71)
    at org.keycloak.storage.AbstractStorageManager.mapEnabledStorageProvidersWithTimeout(AbstractStorageManager.java:135)
    at org.keycloak.storage.UserStorageManager.getUsersCount(UserStorageManager.java:374)
    at org.keycloak.models.cache.infinispan.UserCacheSession.getUsersCount(UserCacheSession.java:545)
    at org.keycloak.storage.user.UserQueryProvider.getUsersCount(UserQueryProvider.java:52)
    at org.keycloak.services.managers.ApplianceBootstrap.createMasterRealmUser(ApplianceBootstrap.java:99)


Solution 1:[1]

We had similar vague error messages when upgrading our embedded keycloak to 15 in our Spring Boot/Servlet-style application. But we eventually fixed them by crawling through the code/history of the project that this baeldung.com tutorial was based; thomasdarimont's Embedded Keycloak Server running in a Spring Boot App. This repo is a few upgrades past the initial tutorial; up to Keycloak 13. We compared the history to our code and applying/testing fixes incrementally for each version from keycloak 11 to 13. After that, the updates from 13 to 15 were a bit easier to understand, and the errors were not as cryptic.

Our application is not exactly like the example code given in the Baeldung tutorial, but below is a list of changes we needed to upgrade to Keycloak 15.0.1. These changes may not be 1:1 with your project, but hopefully these help someone save some time.

  • In KeycloakApplication moved the realm-setup functions from constructor method to bootstrap() method. (An example fix found here)

    
    public class EmbeddedKeycloakApplication extends KeycloakApplication {
    ...
    
     //public EmbeddedKeycloakApplication() {
     //    createMasterRealmAdminUser();
     //    createBaeldungRealm();
     //}
    
     @Override
     protected ExportImportManager bootstrap() {
         final ExportImportManager exportImportManager = super.bootstrap();
         createMasterRealmAdminUser();
         createBaeldungRealm();
         return exportImportManager;
     }
    

  • In the EmbeddedKeycloakConfig we added a couple new bean references/factories (Both found here)

    
    

    public class EmbeddedKeycloakConfig { ...

     @Bean("fixedThreadPool")
     public ExecutorService fixedThreadPool() {
         return Executors.newFixedThreadPool(5);
     }
    
     @Bean
     @ConditionalOnMissingBean(name = "springBootPlatform")
     protected SimplePlatformProvider springBootPlatform() {
         return (SimplePlatformProvider) Platform.getPlatform();
     }
    

  • In our keycloak-server.json, we removed the default 'concurrenthashmap' name from the mapStorage provider, but still provided the concurrenthashmap properties. This matches other Keycloak 15 examples. As Paul mentioned, the map_storage needs to be enabled, and the simplest solution is to use the system properties -Dkeycloak.profile.feature.map_storage=enabled -Dkeycloak.mapStorage.provider=concurrenthashmap. Similar examples can be found in the Keycloak test suites here and here . HOWEVER: We ran into errors when using these system properties, and decided it is not needed for our code. Luckilly, the 'mapStorage' is no specifically called out in the tutorial; it is only found in the Referenced Tutorial Code. So we simply matched other Keycloak 13+ examples and removed the reference in the keycloak-server.json (shown below) to get rid of the null pointer exception.

    
    

    //Change this:

     "mapStorage": {
         "provider": "${keycloak.mapStorage.provider:concurrenthashmap}",
         "concurrenthashmap": {
             "dir": "${project.build.directory:target}"
         }
     },
    

    //To This

     "mapStorage": {
         "provider": "${keycloak.mapStorage.provider:}",
         "concurrenthashmap": {
             "dir": "${project.build.directory:target}"
         } 
     },
    

  • Upgraded the proper infinispan and rest versions with keycloak version. (Tutorial code reference)

    
    

    < properties>

     < keycloak.version>15.0.1</keycloak.version>
    
     < !-- these should be updated together with Keycloak -->
     < !-- check keycloak-dependencies-server-all effective pom -->
     < infinispan.version>11.0.9.Final</infinispan.version>
     < resteasy.version>3.15.1.Final/resteasy.version>
    

    < /properties>

  • We also added the temp directory location in the SimplePlatformProvider, since this field was required. NOTE: The system temp folder, used in the example, is not recommended for production.

    
    
     @Override
     public File getTmpDirectory() {
         return System.getProperty("java.io.tmpdir");
     }
    

I hope someone finds this info useful, Good luck!

Solution 2:[2]

I’ve tried the same thing with keycloak 15 and I got the same result. It seems that keycloak’s ConcurrentHashMapStorageProvider isn’t taken in account.

EDIT: after looking into keycloak's code, I've found that MAP_STORAGE functionality is disabled by default (because the feature is tagged as EXPERIMENTAL). To resolve this issue you must launch your springboot app with the following Java option :

-Dkeycloak.profile.feature.map_storage=enabled

Unfortunately, I'm now facing another nullPointerException...

Solution 3:[3]

I have applied the changes suggested by @mrieman to the initial baeldung.com tutorial. It works fine with 17.0.1 version of Keycloak as of now. Hope it will help someone. My repository on Github is here

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2
Solution 3 Andrey Grigoriev