diff --git a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/ImportRealmMixin.java b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/ImportRealmMixin.java
index 10dc2634b3..1656bbbc5f 100644
--- a/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/ImportRealmMixin.java
+++ b/quarkus/runtime/src/main/java/org/keycloak/quarkus/runtime/cli/command/ImportRealmMixin.java
@@ -20,6 +20,8 @@ package org.keycloak.quarkus.runtime.cli.command;
import static org.keycloak.quarkus.runtime.cli.Picocli.NO_PARAM_LABEL;
import java.io.File;
+
+import org.keycloak.exportimport.ExportImportConfig;
import org.keycloak.quarkus.runtime.Environment;
import picocli.CommandLine;
@@ -39,7 +41,7 @@ public final class ImportRealmMixin {
File importDir = Environment.getHomePath().resolve("data").resolve("import").toFile();
if (importDir.exists()) {
- System.setProperty("keycloak.import", importDir.getAbsolutePath());
+ ExportImportConfig.setDir(importDir.getAbsolutePath());
}
}
}
diff --git a/services/src/main/java/org/keycloak/exportimport/ExportImportConfig.java b/services/src/main/java/org/keycloak/exportimport/ExportImportConfig.java
index 08c26909d3..1b6dfed295 100644
--- a/services/src/main/java/org/keycloak/exportimport/ExportImportConfig.java
+++ b/services/src/main/java/org/keycloak/exportimport/ExportImportConfig.java
@@ -18,6 +18,8 @@
package org.keycloak.exportimport;
import java.io.Closeable;
+import java.util.Optional;
+import java.util.stream.Stream;
/**
* @author Stian Thorgersen
@@ -59,6 +61,18 @@ public class ExportImportConfig {
public static String getAction() {
return System.getProperty(ACTION);
}
+
+ public static String getStrategy() {
+ return System.getProperty(STRATEGY);
+ }
+
+ public static String setStrategy(Strategy strategy) {
+ return System.setProperty(STRATEGY, strategy.toString());
+ }
+
+ public static Optional getDir() {
+ return Optional.ofNullable(System.getProperty(DIR));
+ }
public static Closeable setAction(String exportImportAction) {
System.setProperty(ACTION, exportImportAction);
@@ -92,4 +106,9 @@ public class ExportImportConfig {
public static void setReplacePlaceholders(boolean replacePlaceholders) {
System.setProperty(REPLACE_PLACEHOLDERS, String.valueOf(replacePlaceholders));
}
+
+ public static void reset() {
+ Stream.of(FILE, DIR, ACTION, STRATEGY, REPLACE_PLACEHOLDERS)
+ .forEach(prop -> System.getProperties().remove(prop));
+ }
}
diff --git a/services/src/main/java/org/keycloak/exportimport/ExportImportManager.java b/services/src/main/java/org/keycloak/exportimport/ExportImportManager.java
index 1fc0a9fa81..adab353850 100644
--- a/services/src/main/java/org/keycloak/exportimport/ExportImportManager.java
+++ b/services/src/main/java/org/keycloak/exportimport/ExportImportManager.java
@@ -73,37 +73,36 @@ public class ExportImportManager {
if (importProvider == null) {
throw new RuntimeException("Import provider '" + providerId + "' not found");
}
+ } else if (ExportImportConfig.getDir().isPresent()) { // import at startup
+ ExportImportConfig.setStrategy(Strategy.IGNORE_EXISTING);
+ ExportImportConfig.setReplacePlaceholders(true);
+ // enables logging of what is imported
+ ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
}
}
- public boolean isRunImport() {
- return importProvider != null;
- }
-
public boolean isImportMasterIncluded() {
- if (!isRunImport()) {
- throw new IllegalStateException("Import not enabled");
- }
- try {
- return importProvider.isMasterRealmExported();
- } catch (IOException e) {
- throw new RuntimeException(e);
+ if (importProvider != null) {
+ try {
+ return importProvider.isMasterRealmExported();
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ } else {
+ return isImportMasterIncludedAtStartup();
}
+
}
- public boolean isImportMasterIncludedAtStartup(String dir) {
- if (dir == null) {
- throw new IllegalStateException("Import not enabled");
- }
- ExportImportConfig.setReplacePlaceholders(true);
-
- return getStartupImportProviders(dir).map(Supplier::get).anyMatch(provider -> {
- try {
- return provider.isMasterRealmExported();
- } catch (IOException e) {
- throw new RuntimeException("Failed to run import", e);
- }
- });
+ boolean isImportMasterIncludedAtStartup() {
+ return getStartupImportProviders().map(Supplier::get)
+ .anyMatch(provider -> {
+ try {
+ return provider.isMasterRealmExported();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to run import", e);
+ }
+ });
}
public boolean isRunExport() {
@@ -111,22 +110,19 @@ public class ExportImportManager {
}
public void runImport() {
- try {
- importProvider.importModel();
- } catch (IOException e) {
- throw new RuntimeException("Failed to run import", e);
+ if (importProvider != null) {
+ try {
+ importProvider.importModel();
+ } catch (IOException e) {
+ throw new RuntimeException("Failed to run import", e);
+ }
+ } else {
+ runImportAtStartup();
}
}
- public void runImportAtStartup(String dir) throws IOException {
- System.setProperty(ExportImportConfig.STRATEGY, Strategy.IGNORE_EXISTING.toString());
- ExportImportConfig.setReplacePlaceholders(true);
- // enables logging of what is imported
- ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
-
- // TODO: ideally the static setting above should be unset after this is run
-
- getStartupImportProviders(dir).map(Supplier::get).forEach(ip -> {
+ public void runImportAtStartup() {
+ getStartupImportProviders().map(Supplier::get).forEach(ip -> {
try {
ip.importModel();
} catch (IOException e) {
@@ -135,17 +131,20 @@ public class ExportImportManager {
});
}
- private Stream> getStartupImportProviders(String dir) {
+ private Stream> getStartupImportProviders() {
+ var dirProp = ExportImportConfig.getDir();
+ if (dirProp.isEmpty()) {
+ return Stream.empty();
+ }
+ String dir = dirProp.get();
+
Stream factories = sessionFactory.getProviderFactoriesStream(ImportProvider.class);
return factories.flatMap(factory -> {
String providerId = factory.getId();
if ("dir".equals(providerId)) {
- Supplier func = () -> {
- ExportImportConfig.setDir(dir);
- return session.getProvider(ImportProvider.class, providerId);
- };
+ Supplier func = () -> session.getProvider(ImportProvider.class, providerId);
return Stream.of(func);
}
if ("singleFile".equals(providerId)) {
diff --git a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
index aff7b497a0..90f62adf59 100644
--- a/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
+++ b/services/src/main/java/org/keycloak/services/resources/KeycloakApplication.java
@@ -48,7 +48,6 @@ import java.io.FileInputStream;
import java.io.IOException;
import java.util.List;
import java.util.NoSuchElementException;
-import java.util.Optional;
import java.util.ServiceLoader;
import com.fasterxml.jackson.core.type.TypeReference;
@@ -152,22 +151,18 @@ public abstract class KeycloakApplication extends Application {
var exportImportManager = bootstrapState.exportImportManager = new ExportImportManager(session);
bootstrapState.newInstall = applianceBootstrap.isNewInstall();
if (bootstrapState.newInstall) {
- // check if this is an import command that is importing the master realm
- boolean importingMaster = exportImportManager.isRunImport() && exportImportManager.isImportMasterIncluded();
- // check if this is a start command that is importing the master realm
- importingMaster |= getImportDirectory().filter(exportImportManager::isImportMasterIncludedAtStartup).isPresent();
- if (!importingMaster) {
+ if (!exportImportManager.isImportMasterIncluded()) {
applianceBootstrap.createMasterRealm();
}
// these are also running in the initial bootstrap transaction - if there is a problem, the server won't be initialized at all
- runImports(exportImportManager);
+ exportImportManager.runImport();
createTemporaryAdmin(session);
}
}
});
if (!bootstrapState.newInstall) {
- runImports(bootstrapState.exportImportManager);
+ bootstrapState.exportImportManager.runImport();
}
importAddUser();
@@ -175,14 +170,6 @@ public abstract class KeycloakApplication extends Application {
return bootstrapState.exportImportManager;
}
- private void runImports(ExportImportManager exportImportManager) {
- if (exportImportManager.isRunImport()) {
- exportImportManager.runImport();
- } else {
- importRealms(exportImportManager);
- }
- }
-
protected abstract void createTemporaryAdmin(KeycloakSession session);
protected void loadConfig() {
@@ -205,20 +192,6 @@ public abstract class KeycloakApplication extends Application {
return sessionFactory;
}
- public void importRealms(ExportImportManager exportImportManager) {
- getImportDirectory().ifPresent(dir -> {
- try {
- exportImportManager.runImportAtStartup(dir);
- } catch (IOException cause) {
- throw new RuntimeException("Failed to import realms", cause);
- }
- });
- }
-
- private Optional getImportDirectory() {
- return Optional.ofNullable(System.getProperty("keycloak.import"));
- }
-
public void importRealm(RealmRepresentation rep, String from) {
boolean exists = false;
try (KeycloakSession session = sessionFactory.create()) {
diff --git a/services/src/test/java/org/keycloak/exportimport/ExportImportManagerTest.java b/services/src/test/java/org/keycloak/exportimport/ExportImportManagerTest.java
new file mode 100644
index 0000000000..6b22706ed9
--- /dev/null
+++ b/services/src/test/java/org/keycloak/exportimport/ExportImportManagerTest.java
@@ -0,0 +1,79 @@
+package org.keycloak.exportimport;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import java.io.IOException;
+
+import org.junit.After;
+import org.junit.Test;
+import org.keycloak.models.KeycloakSession;
+import org.keycloak.provider.Provider;
+import org.keycloak.services.DefaultKeycloakContext;
+import org.keycloak.services.DefaultKeycloakSession;
+
+public class ExportImportManagerTest {
+
+ @After
+ public void reset() {
+ ExportImportConfig.reset();
+ }
+
+ @Test
+ public void testImportOnStartup() {
+ ExportImportConfig.setDir("/some/dir");
+ new ExportImportManager(new DefaultKeycloakSession(null) {
+
+ @Override
+ protected DefaultKeycloakContext createKeycloakContext(KeycloakSession session) {
+ return null;
+ }
+
+ });
+ assertEquals(ExportImportConfig.ACTION_IMPORT, ExportImportConfig.getAction());
+ assertEquals(Strategy.IGNORE_EXISTING.toString(), ExportImportConfig.getStrategy());
+ assertTrue(ExportImportConfig.isReplacePlaceholders());
+ }
+
+ @Test
+ public void testImport() {
+ ExportImportConfig.setAction(ExportImportConfig.ACTION_IMPORT);
+ new ExportImportManager(new DefaultKeycloakSession(null) {
+
+ @Override
+ protected DefaultKeycloakContext createKeycloakContext(KeycloakSession session) {
+ return null;
+ }
+
+ @Override
+ public T getProvider(Class clazz, String id) {
+ return (T) new ImportProvider() {
+
+ @Override
+ public void close() {
+
+ }
+
+ @Override
+ public boolean isMasterRealmExported() throws IOException {
+ return false;
+ }
+
+ @Override
+ public void importModel() throws IOException {
+
+ }
+ };
+ }
+
+ });
+ assertEquals(ExportImportConfig.ACTION_IMPORT, ExportImportConfig.getAction());
+ assertNull(ExportImportConfig.getStrategy());
+ // we're now setting this in the Quarkus logic, it's left as false in the ExportImportManager
+ // for arquillian, or other legacy usage
+ assertFalse(ExportImportConfig.isReplacePlaceholders());
+ }
+
+}