Skip to content

Commit

Permalink
KEYCLOAK-1175 Import at startup can fail if master realm not present
Browse files Browse the repository at this point in the history
  • Loading branch information
mposolda committed Jul 11, 2015
1 parent fe1ede2 commit dc366c5
Show file tree
Hide file tree
Showing 7 changed files with 91 additions and 14 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,10 @@ public interface ImportProvider extends Provider {
void importModel(KeycloakSessionFactory factory, Strategy strategy) throws IOException;

void importRealm(KeycloakSessionFactory factory, String realmName, Strategy strategy) throws IOException;

/**
* @return true if master realm was previously exported and is available in the data to be imported
* @throws IOException
*/
boolean isMasterRealmExported() throws IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.keycloak.exportimport.ExportImportConfig;
Expand Down Expand Up @@ -143,6 +144,15 @@ public static void setupMasterAdminManagement(RealmProvider model, RealmModel re
* @throws IOException
*/
public static void importFromStream(KeycloakSession session, ObjectMapper mapper, InputStream is, Strategy strategy) throws IOException {
Map<String, RealmRepresentation> realmReps = getRealmsFromStream(mapper, is);
for (RealmRepresentation realmRep : realmReps.values()) {
importRealm(session, realmRep, strategy);
}
}

public static Map<String, RealmRepresentation> getRealmsFromStream(ObjectMapper mapper, InputStream is) throws IOException {
Map<String, RealmRepresentation> result = new HashMap<String, RealmRepresentation>();

JsonFactory factory = mapper.getJsonFactory();
JsonParser parser = factory.createJsonParser(is);
try {
Expand All @@ -166,18 +176,21 @@ public static void importFromStream(KeycloakSession session, ObjectMapper mapper
}

for (RealmRepresentation realmRep : realmReps) {
importRealm(session, realmRep, strategy);
result.put(realmRep.getId(), realmRep);
}
} else if (parser.getCurrentToken() == JsonToken.START_OBJECT) {
// Case with single realm in stream
RealmRepresentation realmRep = parser.readValueAs(RealmRepresentation.class);
importRealm(session, realmRep, strategy);
result.put(realmRep.getId(), realmRep);
}
} finally {
parser.close();
}

return result;
}


// Assuming that it's invoked inside transaction
public static void importUsersFromStream(KeycloakSession session, String realmName, ObjectMapper mapper, InputStream is) throws IOException {
RealmProvider model = session.realms();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,20 @@ public DirImportProvider(File rootDirectory) {

@Override
public void importModel(KeycloakSessionFactory factory, Strategy strategy) throws IOException {
List<String> realmNames = getRealmsToImport();

for (String realmName : realmNames) {
importRealm(factory, realmName, strategy);
}
}

@Override
public boolean isMasterRealmExported() throws IOException {
List<String> realmNames = getRealmsToImport();
return realmNames.contains(Config.getAdminRealm());
}

private List<String> getRealmsToImport() throws IOException {
File[] realmFiles = this.rootDirectory.listFiles(new FilenameFilter() {

@Override
Expand All @@ -70,10 +84,7 @@ public boolean accept(File dir, String name) {
realmNames.add(realmName);
}
}

for (String realmName : realmNames) {
importRealm(factory, realmName, strategy);
}
return realmNames;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package org.keycloak.exportimport.singlefile;

import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.exportimport.ImportProvider;
import org.keycloak.exportimport.Strategy;
import org.keycloak.exportimport.util.ExportImportSessionTask;
import org.keycloak.exportimport.util.ImportUtils;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.util.JsonSerialization;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Map;

/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
Expand All @@ -23,24 +26,43 @@ public class SingleFileImportProvider implements ImportProvider {

private File file;

// Allows to cache representation per provider to avoid parsing them twice
protected Map<String, RealmRepresentation> realmReps;

public SingleFileImportProvider(File file) {
this.file = file;
}

@Override
public void importModel(KeycloakSessionFactory factory, final Strategy strategy) throws IOException {
logger.infof("Full importing from file %s", this.file.getAbsolutePath());
checkRealmReps();

KeycloakModelUtils.runJobInTransaction(factory, new ExportImportSessionTask() {

@Override
protected void runExportImportTask(KeycloakSession session) throws IOException {
FileInputStream is = new FileInputStream(file);
ImportUtils.importFromStream(session, JsonSerialization.mapper, is, strategy);
for (RealmRepresentation realmRep : realmReps.values()) {
ImportUtils.importRealm(session, realmRep, strategy);
}
}

});
}

@Override
public boolean isMasterRealmExported() throws IOException {
checkRealmReps();
return (realmReps.containsKey(Config.getAdminRealm()));
}

protected void checkRealmReps() throws IOException {
if (realmReps == null) {
FileInputStream is = new FileInputStream(file);
realmReps = ImportUtils.getRealmsFromStream(JsonSerialization.mapper, is);
}
}

@Override
public void importRealm(KeycloakSessionFactory factory, String realmName, Strategy strategy) throws IOException {
// TODO: import just that single realm in case that file contains many realms?
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,20 @@ public ZipImportProvider(File zipFile, String password) {

@Override
public void importModel(KeycloakSessionFactory factory, Strategy strategy) throws IOException {
List<String> realmNames = getRealmsToImport();

for (String realmName : realmNames) {
importRealm(factory, realmName, strategy);
}
}

@Override
public boolean isMasterRealmExported() throws IOException {
List<String> realmNames = getRealmsToImport();
return realmNames.contains(Config.getAdminRealm());
}

private List<String> getRealmsToImport() throws IOException {
List<String> realmNames = new ArrayList<String>();
for (ExtZipEntry entry : this.decrypter.getEntryList()) {
String entryName = entry.getName();
Expand All @@ -66,10 +80,7 @@ public void importModel(KeycloakSessionFactory factory, Strategy strategy) throw
}
}
}

for (String realmName : realmNames) {
importRealm(factory, realmName, strategy);
}
return realmNames;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,10 @@


import org.jboss.logging.Logger;
import org.keycloak.Config;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.KeycloakSessionFactory;
import org.keycloak.services.managers.ApplianceBootstrap;

/**
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
Expand All @@ -12,7 +14,7 @@ public class ExportImportManager {

private static final Logger logger = Logger.getLogger(ExportImportManager.class);

public void checkExportImport(KeycloakSessionFactory sessionFactory) {
public void checkExportImport(KeycloakSessionFactory sessionFactory, String contextPath) {
String exportImportAction = ExportImportConfig.getAction();
String realmName = ExportImportConfig.getRealmName();

Expand Down Expand Up @@ -46,9 +48,21 @@ public void checkExportImport(KeycloakSessionFactory sessionFactory) {
Strategy strategy = ExportImportConfig.getStrategy();
if (realmName == null) {
logger.infof("Full model import requested. Strategy: %s", strategy.toString());

// Check if master realm was exported. If it's not, then it needs to be created before other realms are imported
if (!importProvider.isMasterRealmExported()) {
new ApplianceBootstrap().bootstrap(sessionFactory, contextPath);
}

importProvider.importModel(sessionFactory, strategy);
} else {
logger.infof("Import of realm '%s' requested. Strategy: %s", realmName, strategy.toString());

if (!realmName.equals(Config.getAdminRealm())) {
// Check if master realm exists. If it's not, then it needs to be created before other realm is imported
new ApplianceBootstrap().bootstrap(sessionFactory, contextPath);
}

importProvider.importRealm(sessionFactory, realmName, strategy);
}
logger.info("Import finished successfully");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,7 +83,7 @@ public KeycloakApplication(@Context ServletContext context, @Context Dispatcher
classes.add(JsResource.class);
classes.add(WelcomeResource.class);

new ExportImportManager().checkExportImport(this.sessionFactory);
new ExportImportManager().checkExportImport(this.sessionFactory, context.getContextPath());

setupDefaultRealm(context.getContextPath());

Expand Down

0 comments on commit dc366c5

Please sign in to comment.