keycloak: MigrateT021_0_0 fails with NPE if adminTheme is not configured explictly

Before reporting an issue

  • I have searched existing issues
  • I have reproduced the issue with the latest release

Area

core

Describe the bug

Server fails to start with database which contains realms that have no explict admin-console theme configured due to a missing null-check in the migration here: https://github.com/keycloak/keycloak/blob/557a22968cf36ef67ec02971e3b93c785c5853ec/model/legacy-private/src/main/java/org/keycloak/migration/migrators/MigrateTo21_0_0.java#L28

Version

21.0.0

Expected behavior

Migration should pass

Actual behavior

Server crashes

How to Reproduce?

  1. Create a realm without explict admin-console configuration in an older keycloak version
  2. Run Keycloak 21.0.0 against the same database.

Anything else?

dev-acme-keycloak-1               | 13:11:33 ERROR traceId=, parentId=, spanId=, sampled= [or.ke.qu.ru.cl.ExecutionExceptionHandler] (main) ERROR: Failed to start server in (development) mode
dev-acme-keycloak-1               | 13:11:33 ERROR traceId=, parentId=, spanId=, sampled= [or.ke.qu.ru.cl.ExecutionExceptionHandler] (main) Error details:: java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because "adminTheme" is null
dev-acme-keycloak-1               | 	at org.keycloak.migration.migrators.MigrateTo21_0_0.updateAdminTheme(MigrateTo21_0_0.java:28)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
dev-acme-keycloak-1               | 	at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
dev-acme-keycloak-1               | 	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1845)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
dev-acme-keycloak-1               | 	at org.hibernate.query.spi.StreamDecorator.forEach(StreamDecorator.java:153)
dev-acme-keycloak-1               | 	at org.keycloak.utils.ClosingStream.forEach(ClosingStream.java:128)
dev-acme-keycloak-1               | 	at org.keycloak.migration.migrators.MigrateTo21_0_0.migrate(MigrateTo21_0_0.java:18)
dev-acme-keycloak-1               | 	at org.keycloak.storage.datastore.LegacyMigrationManager.migrate(LegacyMigrationManager.java:135)
dev-acme-keycloak-1               | 	at org.keycloak.migration.MigrationModelManager.migrate(MigrationModelManager.java:33)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.storage.legacy.database.LegacyJpaConnectionProviderFactory.migrateModel(LegacyJpaConnectionProviderFactory.java:216)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.storage.legacy.database.LegacyJpaConnectionProviderFactory.initSchema(LegacyJpaConnectionProviderFactory.java:210)
dev-acme-keycloak-1               | 	at org.keycloak.models.utils.KeycloakModelUtils.lambda$runJobInTransaction$1(KeycloakModelUtils.java:256)
dev-acme-keycloak-1               | 	at org.keycloak.models.utils.KeycloakModelUtils.runJobInTransactionWithResult(KeycloakModelUtils.java:269)
dev-acme-keycloak-1               | 	at org.keycloak.models.utils.KeycloakModelUtils.runJobInTransaction(KeycloakModelUtils.java:255)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.storage.legacy.database.LegacyJpaConnectionProviderFactory.postInit(LegacyJpaConnectionProviderFactory.java:135)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.integration.QuarkusKeycloakSessionFactory.init(QuarkusKeycloakSessionFactory.java:105)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.integration.jaxrs.QuarkusKeycloakApplication.createSessionFactory(QuarkusKeycloakApplication.java:41)
dev-acme-keycloak-1               | 	at org.keycloak.services.resources.KeycloakApplication.startup(KeycloakApplication.java:124)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.integration.QuarkusLifecycleObserver.onStartupEvent(QuarkusLifecycleObserver.java:37)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.integration.QuarkusLifecycleObserver_Observer_onStartupEvent_b0e82415b143738dc1f986a5fa4668e83d0a5dea.notify(Unknown Source)
dev-acme-keycloak-1               | 	at io.quarkus.arc.impl.EventImpl$Notifier.notifyObservers(EventImpl.java:326)
dev-acme-keycloak-1               | 	at io.quarkus.arc.impl.EventImpl$Notifier.notify(EventImpl.java:308)
dev-acme-keycloak-1               | 	at io.quarkus.arc.impl.EventImpl.fire(EventImpl.java:76)
dev-acme-keycloak-1               | 	at io.quarkus.arc.runtime.ArcRecorder.fireLifecycleEvent(ArcRecorder.java:131)
dev-acme-keycloak-1               | 	at io.quarkus.arc.runtime.ArcRecorder.handleLifecycleEvents(ArcRecorder.java:100)
dev-acme-keycloak-1               | 	at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy_0(Unknown Source)
dev-acme-keycloak-1               | 	at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy(Unknown Source)
dev-acme-keycloak-1               | 	at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)
dev-acme-keycloak-1               | 	at io.quarkus.runtime.Application.start(Application.java:101)
dev-acme-keycloak-1               | 	at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:110)
dev-acme-keycloak-1               | 	at io.quarkus.runtime.Quarkus.run(Quarkus.java:70)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.KeycloakMain.start(KeycloakMain.java:102)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.run(AbstractStartCommand.java:37)
dev-acme-keycloak-1               | 	at picocli.CommandLine.executeUserObject(CommandLine.java:1939)
dev-acme-keycloak-1               | 	at picocli.CommandLine.access$1300(CommandLine.java:145)
dev-acme-keycloak-1               | 	at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2358)
dev-acme-keycloak-1               | 	at picocli.CommandLine$RunLast.handle(CommandLine.java:2352)
dev-acme-keycloak-1               | 	at picocli.CommandLine$RunLast.handle(CommandLine.java:2314)
dev-acme-keycloak-1               | 	at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2179)
dev-acme-keycloak-1               | 	at picocli.CommandLine$RunLast.execute(CommandLine.java:2316)
dev-acme-keycloak-1               | 	at picocli.CommandLine.execute(CommandLine.java:2078)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.cli.Picocli.parseAndRun(Picocli.java:93)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.KeycloakMain.main(KeycloakMain.java:88)
dev-acme-keycloak-1               | 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
dev-acme-keycloak-1               | 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
dev-acme-keycloak-1               | 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
dev-acme-keycloak-1               | 	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
dev-acme-keycloak-1               | 	at io.quarkus.bootstrap.runner.QuarkusEntryPoint.doRun(QuarkusEntryPoint.java:61)
dev-acme-keycloak-1               | 	at io.quarkus.bootstrap.runner.QuarkusEntryPoint.main(QuarkusEntryPoint.java:32)
dev-acme-keycloak-1               | 13:11:33 ERROR traceId=, parentId=, spanId=, sampled= [or.ke.qu.ru.cl.ExecutionExceptionHandler] (main) ERROR: Failed to start server in (development) mode
dev-acme-keycloak-1               | 13:11:33 ERROR traceId=, parentId=, spanId=, sampled= [or.ke.qu.ru.cl.ExecutionExceptionHandler] (main) Error details:: java.lang.NullPointerException: Cannot invoke "String.equals(Object)" because "adminTheme" is null
dev-acme-keycloak-1               | 	at org.keycloak.migration.migrators.MigrateTo21_0_0.updateAdminTheme(MigrateTo21_0_0.java:28)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:183)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197)
dev-acme-keycloak-1               | 	at java.base/java.util.Iterator.forEachRemaining(Iterator.java:133)
dev-acme-keycloak-1               | 	at java.base/java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1845)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:150)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:173)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
dev-acme-keycloak-1               | 	at java.base/java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:596)
dev-acme-keycloak-1               | 	at org.hibernate.query.spi.StreamDecorator.forEach(StreamDecorator.java:153)
dev-acme-keycloak-1               | 	at org.keycloak.utils.ClosingStream.forEach(ClosingStream.java:128)
dev-acme-keycloak-1               | 	at org.keycloak.migration.migrators.MigrateTo21_0_0.migrate(MigrateTo21_0_0.java:18)
dev-acme-keycloak-1               | 	at org.keycloak.storage.datastore.LegacyMigrationManager.migrate(LegacyMigrationManager.java:135)
dev-acme-keycloak-1               | 	at org.keycloak.migration.MigrationModelManager.migrate(MigrationModelManager.java:33)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.storage.legacy.database.LegacyJpaConnectionProviderFactory.migrateModel(LegacyJpaConnectionProviderFactory.java:216)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.storage.legacy.database.LegacyJpaConnectionProviderFactory.initSchema(LegacyJpaConnectionProviderFactory.java:210)
dev-acme-keycloak-1               | 	at org.keycloak.models.utils.KeycloakModelUtils.lambda$runJobInTransaction$1(KeycloakModelUtils.java:256)
dev-acme-keycloak-1               | 	at org.keycloak.models.utils.KeycloakModelUtils.runJobInTransactionWithResult(KeycloakModelUtils.java:269)
dev-acme-keycloak-1               | 	at org.keycloak.models.utils.KeycloakModelUtils.runJobInTransaction(KeycloakModelUtils.java:255)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.storage.legacy.database.LegacyJpaConnectionProviderFactory.postInit(LegacyJpaConnectionProviderFactory.java:135)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.integration.QuarkusKeycloakSessionFactory.init(QuarkusKeycloakSessionFactory.java:105)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.integration.jaxrs.QuarkusKeycloakApplication.createSessionFactory(QuarkusKeycloakApplication.java:41)
dev-acme-keycloak-1               | 	at org.keycloak.services.resources.KeycloakApplication.startup(KeycloakApplication.java:124)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.integration.QuarkusLifecycleObserver.onStartupEvent(QuarkusLifecycleObserver.java:37)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.integration.QuarkusLifecycleObserver_Observer_onStartupEvent_b0e82415b143738dc1f986a5fa4668e83d0a5dea.notify(Unknown Source)
dev-acme-keycloak-1               | 	at io.quarkus.arc.impl.EventImpl$Notifier.notifyObservers(EventImpl.java:326)
dev-acme-keycloak-1               | 	at io.quarkus.arc.impl.EventImpl$Notifier.notify(EventImpl.java:308)
dev-acme-keycloak-1               | 	at io.quarkus.arc.impl.EventImpl.fire(EventImpl.java:76)
dev-acme-keycloak-1               | 	at io.quarkus.arc.runtime.ArcRecorder.fireLifecycleEvent(ArcRecorder.java:131)
dev-acme-keycloak-1               | 	at io.quarkus.arc.runtime.ArcRecorder.handleLifecycleEvents(ArcRecorder.java:100)
dev-acme-keycloak-1               | 	at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy_0(Unknown Source)
dev-acme-keycloak-1               | 	at io.quarkus.deployment.steps.LifecycleEventsBuildStep$startupEvent1144526294.deploy(Unknown Source)
dev-acme-keycloak-1               | 	at io.quarkus.runner.ApplicationImpl.doStart(Unknown Source)
dev-acme-keycloak-1               | 	at io.quarkus.runtime.Application.start(Application.java:101)
dev-acme-keycloak-1               | 	at io.quarkus.runtime.ApplicationLifecycleManager.run(ApplicationLifecycleManager.java:110)
dev-acme-keycloak-1               | 	at io.quarkus.runtime.Quarkus.run(Quarkus.java:70)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.KeycloakMain.start(KeycloakMain.java:102)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.cli.command.AbstractStartCommand.run(AbstractStartCommand.java:37)
dev-acme-keycloak-1               | 	at picocli.CommandLine.executeUserObject(CommandLine.java:1939)
dev-acme-keycloak-1               | 	at picocli.CommandLine.access$1300(CommandLine.java:145)
dev-acme-keycloak-1               | 	at picocli.CommandLine$RunLast.executeUserObjectOfLastSubcommandWithSameParent(CommandLine.java:2358)
dev-acme-keycloak-1               | 	at picocli.CommandLine$RunLast.handle(CommandLine.java:2352)
dev-acme-keycloak-1               | 	at picocli.CommandLine$RunLast.handle(CommandLine.java:2314)
dev-acme-keycloak-1               | 	at picocli.CommandLine$AbstractParseResultHandler.execute(CommandLine.java:2179)
dev-acme-keycloak-1               | 	at picocli.CommandLine$RunLast.execute(CommandLine.java:2316)
dev-acme-keycloak-1               | 	at picocli.CommandLine.execute(CommandLine.java:2078)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.cli.Picocli.parseAndRun(Picocli.java:93)
dev-acme-keycloak-1               | 	at org.keycloak.quarkus.runtime.KeycloakMain.main(KeycloakMain.java:88)
dev-acme-keycloak-1               | 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
dev-acme-keycloak-1               | 	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:77)
dev-acme-keycloak-1               | 	at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
dev-acme-keycloak-1               | 	at java.base/java.lang.reflect.Method.invoke(Method.java:568)
dev-acme-keycloak-1               | 	at io.quarkus.bootstrap.runner.QuarkusEntryPoint.doRun(QuarkusEntryPoint.java:61)
dev-acme-keycloak-1               | 	at io.quarkus.bootstrap.runner.QuarkusEntryPoint.main(QuarkusEntryPoint.java:32)

About this issue

  • Original URL
  • State: closed
  • Created a year ago
  • Comments: 15 (4 by maintainers)

Commits related to this issue

Most upvoted comments

Another workaround may be, if you have access to the database, to execute this statement: update realm set admin_theme = 'keycloak' where admin_theme is null

@stianst I think this is a candidate for a 21.0.1 bugfix release, since this can affect many users

@logopk Your MySQL database is probably using uppercase for table and column names, try:

update REALM set ADMIN_THEME = 'keycloak' where ADMIN_THEME is null;

One-Liner for Keycloak PostgreSQL database running as an container:

# Replace keycloak-keycloakdb-1 with your keycloak database container name
docker exec -it keycloak-keycloakdb-1 psql --username=keycloak -c "UPDATE REALM SET ADMIN_THEME='keycloak' WHERE ADMIN_THEME IS NULL;";