Skip to content

Commit

Permalink
KEYCLOAK-1789 KEYCLOAK-1759 Export/import fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
mposolda committed Sep 2, 2015
1 parent d9e3308 commit 5b9d128
Show file tree
Hide file tree
Showing 14 changed files with 158 additions and 88 deletions.
Expand Up @@ -14,6 +14,7 @@
import org.keycloak.models.RealmProvider; import org.keycloak.models.RealmProvider;
import org.keycloak.models.RoleModel; import org.keycloak.models.RoleModel;
import org.keycloak.models.utils.KeycloakModelUtils; import org.keycloak.models.utils.KeycloakModelUtils;
import org.keycloak.models.utils.RealmImporter;
import org.keycloak.models.utils.RepresentationToModel; import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation; import org.keycloak.representations.idm.UserRepresentation;
Expand Down Expand Up @@ -76,11 +77,8 @@ public static void importRealm(KeycloakSession session, RealmRepresentation rep,
} }
} }


realm = rep.getId() != null ? model.createRealm(rep.getId(), realmName) : model.createRealm(realmName); RealmImporter realmManager = session.getContext().getRealmManager();

realm = realmManager.importRealm(rep);
RepresentationToModel.importRealm(session, rep, realm);

refreshMasterAdminApps(model, realm);


if (System.getProperty(ExportImportConfig.ACTION) != null) { if (System.getProperty(ExportImportConfig.ACTION) != null) {
logger.infof("Realm '%s' imported", realmName); logger.infof("Realm '%s' imported", realmName);
Expand All @@ -89,64 +87,6 @@ public static void importRealm(KeycloakSession session, RealmRepresentation rep,
return; return;
} }


private static void refreshMasterAdminApps(RealmProvider model, RealmModel realm) {
String adminRealmId = Config.getAdminRealm();
if (adminRealmId.equals(realm.getId())) {
// We just imported master realm. All 'masterAdminApps' need to be refreshed
RealmModel adminRealm = realm;
for (RealmModel currentRealm : model.getRealms()) {
ClientModel masterApp = adminRealm.getClientByClientId(KeycloakModelUtils.getMasterRealmAdminApplicationClientId(currentRealm));
if (masterApp != null) {
currentRealm.setMasterAdminClient(masterApp);
} else {
setupMasterAdminManagement(model, currentRealm);
}
}
} else {
// Need to refresh masterApp for current realm
RealmModel adminRealm = model.getRealm(adminRealmId);
ClientModel masterApp = adminRealm.getClientByClientId(KeycloakModelUtils.getMasterRealmAdminApplicationClientId(realm));
if (masterApp != null) {
realm.setMasterAdminClient(masterApp);
} else {
setupMasterAdminManagement(model, realm);
}
}
}

// TODO: We need method here, so we are able to refresh masterAdmin applications after import. Should be RealmManager moved to model/api instead?
public static void setupMasterAdminManagement(RealmProvider model, RealmModel realm) {
RealmModel adminRealm;
RoleModel adminRole;

if (realm.getName().equals(Config.getAdminRealm())) {
adminRealm = realm;

adminRole = realm.addRole(AdminRoles.ADMIN);

RoleModel createRealmRole = realm.addRole(AdminRoles.CREATE_REALM);
adminRole.addCompositeRole(createRealmRole);
createRealmRole.setDescription("${role_"+AdminRoles.CREATE_REALM+"}");
} else {
adminRealm = model.getRealmByName(Config.getAdminRealm());
adminRole = adminRealm.getRole(AdminRoles.ADMIN);
}
adminRole.setDescription("${role_"+AdminRoles.ADMIN+"}");

ClientModel realmAdminApp = KeycloakModelUtils.createClient(adminRealm, KeycloakModelUtils.getMasterRealmAdminApplicationClientId(realm));
// No localized name for now
realmAdminApp.setName(realm.getName() + " Realm");
realmAdminApp.setBearerOnly(true);
realm.setMasterAdminClient(realmAdminApp);

for (String r : AdminRoles.ALL_REALM_ROLES) {
RoleModel role = realmAdminApp.addRole(r);
role.setDescription("${role_"+r+"}");
adminRole.addCompositeRole(role);
}
}


/** /**
* Fully import realm (or more realms from particular stream) * Fully import realm (or more realms from particular stream)
* *
Expand Down Expand Up @@ -187,12 +127,12 @@ public static Map<String, RealmRepresentation> getRealmsFromStream(ObjectMapper
} }


for (RealmRepresentation realmRep : realmReps) { for (RealmRepresentation realmRep : realmReps) {
result.put(realmRep.getId(), realmRep); result.put(realmRep.getRealm(), realmRep);
} }
} else if (parser.getCurrentToken() == JsonToken.START_OBJECT) { } else if (parser.getCurrentToken() == JsonToken.START_OBJECT) {
// Case with single realm in stream // Case with single realm in stream
RealmRepresentation realmRep = parser.readValueAs(RealmRepresentation.class); RealmRepresentation realmRep = parser.readValueAs(RealmRepresentation.class);
result.put(realmRep.getId(), realmRep); result.put(realmRep.getRealm(), realmRep);
} }
} finally { } finally {
parser.close(); parser.close();
Expand Down
Expand Up @@ -22,7 +22,7 @@ public static void setupMasterRealmRole(RealmProvider model, RealmModel realm) {
adminRealm = model.getRealmByName(Config.getAdminRealm()); adminRealm = model.getRealmByName(Config.getAdminRealm());
adminRole = adminRealm.getRole(AdminRoles.ADMIN); adminRole = adminRealm.getRole(AdminRoles.ADMIN);
} }
ClientModel realmAdminApp = adminRealm.getClientByClientId(KeycloakModelUtils.getMasterRealmAdminApplicationClientId(realm)); ClientModel realmAdminApp = adminRealm.getClientByClientId(KeycloakModelUtils.getMasterRealmAdminApplicationClientId(realm.getName()));
if (realmAdminApp.getRole(IMPERSONATION_ROLE) != null) return; if (realmAdminApp.getRole(IMPERSONATION_ROLE) != null) return;
RoleModel impersonationRole = realmAdminApp.addRole(IMPERSONATION_ROLE); RoleModel impersonationRole = realmAdminApp.addRole(IMPERSONATION_ROLE);
impersonationRole.setDescription("${role_" + IMPERSONATION_ROLE + "}"); impersonationRole.setDescription("${role_" + IMPERSONATION_ROLE + "}");
Expand Down
@@ -1,6 +1,7 @@
package org.keycloak.models; package org.keycloak.models;


import org.keycloak.ClientConnection; import org.keycloak.ClientConnection;
import org.keycloak.models.utils.RealmImporter;


import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
import javax.ws.rs.core.UriInfo; import javax.ws.rs.core.UriInfo;
Expand Down Expand Up @@ -30,4 +31,6 @@ public interface KeycloakContext {


void setConnection(ClientConnection connection); void setConnection(ClientConnection connection);


RealmImporter getRealmManager();

} }
Expand Up @@ -257,8 +257,8 @@ public static void runJobInTransaction(KeycloakSessionFactory factory, KeycloakS
} }
} }


public static String getMasterRealmAdminApplicationClientId(RealmModel realm) { public static String getMasterRealmAdminApplicationClientId(String realmName) {
return realm.getName() + "-realm"; return realmName + "-realm";
} }


/** /**
Expand Down
@@ -0,0 +1,14 @@
package org.keycloak.models.utils;

import org.keycloak.models.RealmModel;
import org.keycloak.representations.idm.RealmRepresentation;

/**
* Helper interface used just because RealmManager is in keycloak-services and not accessible for ImportUtils
*
* @author <a href="mailto:mposolda@redhat.com">Marek Posolda</a>
*/
public interface RealmImporter {

RealmModel importRealm(RealmRepresentation rep);
}
Expand Up @@ -779,7 +779,7 @@ public void setAdminEventsDetailsEnabled(boolean enabled) {


@Override @Override
public ClientModel getMasterAdminClient() { public ClientModel getMasterAdminClient() {
return cacheSession.getRealm(Config.getAdminRealm()).getClientById(cached.getMasterAdminClient()); return cached.getMasterAdminClient()==null ? null : cacheSession.getRealm(Config.getAdminRealm()).getClientById(cached.getMasterAdminClient());
} }


@Override @Override
Expand Down
Expand Up @@ -187,7 +187,8 @@ public CachedRealm(RealmCache cache, RealmProvider delegate, RealmModel model) {
adminEventsDetailsEnabled = model.isAdminEventsDetailsEnabled(); adminEventsDetailsEnabled = model.isAdminEventsDetailsEnabled();


defaultRoles.addAll(model.getDefaultRoles()); defaultRoles.addAll(model.getDefaultRoles());
masterAdminClient = model.getMasterAdminClient().getId(); ClientModel masterAdminClient = model.getMasterAdminClient();
this.masterAdminClient = (masterAdminClient != null) ? masterAdminClient.getId() : null;


for (RoleModel role : model.getRoles()) { for (RoleModel role : model.getRoles()) {
realmRoles.put(role.getName(), role.getId()); realmRoles.put(role.getName(), role.getId());
Expand Down
Expand Up @@ -1171,7 +1171,8 @@ public void setAdminEventsDetailsEnabled(boolean enabled) {


@Override @Override
public ClientModel getMasterAdminClient() { public ClientModel getMasterAdminClient() {
return new ClientAdapter(this, em, session, realm.getMasterAdminClient()); ClientEntity client = realm.getMasterAdminClient();
return client!=null ? new ClientAdapter(this, em, session, realm.getMasterAdminClient()) : null;
} }


@Override @Override
Expand Down
Expand Up @@ -35,14 +35,18 @@ public void checkExportImport(KeycloakSessionFactory sessionFactory, String cont
if (export) { if (export) {
ExportProvider exportProvider = session.getProvider(ExportProvider.class, exportImportProviderId); ExportProvider exportProvider = session.getProvider(ExportProvider.class, exportImportProviderId);


if (realmName == null) { if (exportProvider == null) {
logger.info("Full model export requested"); logger.errorf("Invalid Export Provider %s", exportImportProviderId);
exportProvider.exportModel(sessionFactory);
} else { } else {
logger.infof("Export of realm '%s' requested", realmName); if (realmName == null) {
exportProvider.exportRealm(sessionFactory, realmName); logger.info("Full model export requested");
exportProvider.exportModel(sessionFactory);
} else {
logger.infof("Export of realm '%s' requested", realmName);
exportProvider.exportRealm(sessionFactory, realmName);
}
logger.info("Export finished successfully");
} }
logger.info("Export finished successfully");
} else { } else {
ImportProvider importProvider = session.getProvider(ImportProvider.class, exportImportProviderId); ImportProvider importProvider = session.getProvider(ImportProvider.class, exportImportProviderId);


Expand Down
Expand Up @@ -4,7 +4,10 @@
import org.keycloak.ClientConnection; import org.keycloak.ClientConnection;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
import org.keycloak.models.KeycloakContext; import org.keycloak.models.KeycloakContext;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel; import org.keycloak.models.RealmModel;
import org.keycloak.models.utils.RealmImporter;
import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.KeycloakApplication; import org.keycloak.services.resources.KeycloakApplication;


import javax.ws.rs.core.HttpHeaders; import javax.ws.rs.core.HttpHeaders;
Expand All @@ -21,6 +24,12 @@ public class DefaultKeycloakContext implements KeycloakContext {


private ClientConnection connection; private ClientConnection connection;


private KeycloakSession session;

public DefaultKeycloakContext(KeycloakSession session) {
this.session = session;
}

@Override @Override
public String getContextPath() { public String getContextPath() {
KeycloakApplication app = getContextObject(KeycloakApplication.class); KeycloakApplication app = getContextObject(KeycloakApplication.class);
Expand Down Expand Up @@ -71,4 +80,11 @@ public ClientConnection getConnection() {
public void setConnection(ClientConnection connection) { public void setConnection(ClientConnection connection) {
this.connection = connection; this.connection = connection;
} }

@Override
public RealmImporter getRealmManager() {
RealmManager manager = new RealmManager(session);
manager.setContextPath(getContextPath());
return manager;
}
} }
Expand Up @@ -46,7 +46,7 @@ public DefaultKeycloakSession(DefaultKeycloakSessionFactory factory) {
this.factory = factory; this.factory = factory;
this.transactionManager = new DefaultKeycloakTransactionManager(); this.transactionManager = new DefaultKeycloakTransactionManager();
federationManager = new UserFederationManager(this); federationManager = new UserFederationManager(this);
context = new DefaultKeycloakContext(); context = new DefaultKeycloakContext(this);
} }


@Override @Override
Expand Down
Expand Up @@ -3,7 +3,7 @@
import org.jboss.logging.Logger; import org.jboss.logging.Logger;
import org.keycloak.Config; import org.keycloak.Config;
import org.keycloak.enums.SslRequired; import org.keycloak.enums.SslRequired;
import org.keycloak.exportimport.util.ImportUtils; import org.keycloak.models.utils.RealmImporter;
import org.keycloak.models.AccountRoles; import org.keycloak.models.AccountRoles;
import org.keycloak.models.AdminRoles; import org.keycloak.models.AdminRoles;
import org.keycloak.models.ClientModel; import org.keycloak.models.ClientModel;
Expand Down Expand Up @@ -39,7 +39,7 @@
* @author <a href="mailto:bill@burkecentral.com">Bill Burke</a> * @author <a href="mailto:bill@burkecentral.com">Bill Burke</a>
* @version $Revision: 1 $ * @version $Revision: 1 $
*/ */
public class RealmManager { public class RealmManager implements RealmImporter {
protected static final Logger logger = Logger.getLogger(RealmManager.class); protected static final Logger logger = Logger.getLogger(RealmManager.class);


protected KeycloakSession session; protected KeycloakSession session;
Expand Down Expand Up @@ -161,7 +161,9 @@ public boolean removeRealm(RealmModel realm) {


boolean removed = model.removeRealm(realm.getId()); boolean removed = model.removeRealm(realm.getId());
if (removed) { if (removed) {
new ClientManager(this).removeClient(getKeycloakAdminstrationRealm(), realm.getMasterAdminClient()); if (realm.getMasterAdminClient() != null) {
new ClientManager(this).removeClient(getKeycloakAdminstrationRealm(), realm.getMasterAdminClient());
}


UserSessionProvider sessions = session.sessions(); UserSessionProvider sessions = session.sessions();
if (sessions != null) { if (sessions != null) {
Expand Down Expand Up @@ -191,9 +193,47 @@ public void updateRealmEventsConfig(RealmEventsConfigRepresentation rep, RealmMo
realm.setAdminEventsDetailsEnabled(rep.isAdminEventsDetailsEnabled()); realm.setAdminEventsDetailsEnabled(rep.isAdminEventsDetailsEnabled());
} }


// Should be RealmManager moved to model/api instead of referencing methods this way?
private void setupMasterAdminManagement(RealmModel realm) { private void setupMasterAdminManagement(RealmModel realm) {
ImportUtils.setupMasterAdminManagement(model, realm); // Need to refresh masterApp for current realm
String adminRealmId = Config.getAdminRealm();
RealmModel adminRealm = model.getRealm(adminRealmId);
ClientModel masterApp = adminRealm.getClientByClientId(KeycloakModelUtils.getMasterRealmAdminApplicationClientId(realm.getName()));
if (masterApp != null) {
realm.setMasterAdminClient(masterApp);
} else {
createMasterAdminManagement(model, realm);
}
}

private void createMasterAdminManagement(RealmProvider model, RealmModel realm) {
RealmModel adminRealm;
RoleModel adminRole;

if (realm.getName().equals(Config.getAdminRealm())) {
adminRealm = realm;

adminRole = realm.addRole(AdminRoles.ADMIN);

RoleModel createRealmRole = realm.addRole(AdminRoles.CREATE_REALM);
adminRole.addCompositeRole(createRealmRole);
createRealmRole.setDescription("${role_"+AdminRoles.CREATE_REALM+"}");
} else {
adminRealm = model.getRealmByName(Config.getAdminRealm());
adminRole = adminRealm.getRole(AdminRoles.ADMIN);
}
adminRole.setDescription("${role_"+AdminRoles.ADMIN+"}");

ClientModel realmAdminApp = KeycloakModelUtils.createClient(adminRealm, KeycloakModelUtils.getMasterRealmAdminApplicationClientId(realm.getName()));
// No localized name for now
realmAdminApp.setName(realm.getName() + " Realm");
realmAdminApp.setBearerOnly(true);
realm.setMasterAdminClient(realmAdminApp);

for (String r : AdminRoles.ALL_REALM_ROLES) {
RoleModel role = realmAdminApp.addRole(r);
role.setDescription("${role_"+r+"}");
adminRole.addCompositeRole(role);
}
} }


private void setupRealmAdminManagement(RealmModel realm) { private void setupRealmAdminManagement(RealmModel realm) {
Expand Down Expand Up @@ -257,6 +297,7 @@ public void setupBrokerService(RealmModel realm) {
} }
} }


@Override
public RealmModel importRealm(RealmRepresentation rep) { public RealmModel importRealm(RealmRepresentation rep) {
String id = rep.getId(); String id = rep.getId();
if (id == null) { if (id == null) {
Expand All @@ -268,7 +309,12 @@ public RealmModel importRealm(RealmRepresentation rep) {
// setup defaults // setup defaults


setupRealmDefaults(realm); setupRealmDefaults(realm);
setupMasterAdminManagement(realm);
boolean postponeMasterClientSetup = postponeMasterClientSetup(rep);
if (!postponeMasterClientSetup) {
setupMasterAdminManagement(realm);
}

if (!hasRealmAdminManagementClient(rep)) setupRealmAdminManagement(realm); if (!hasRealmAdminManagementClient(rep)) setupRealmAdminManagement(realm);
if (!hasAccountManagementClient(rep)) setupAccountManagement(realm); if (!hasAccountManagementClient(rep)) setupAccountManagement(realm);


Expand All @@ -286,6 +332,10 @@ public RealmModel importRealm(RealmRepresentation rep) {


RepresentationToModel.importRealm(session, rep, realm); RepresentationToModel.importRealm(session, rep, realm);


if (postponeMasterClientSetup) {
setupMasterAdminManagement(realm);
}

// Could happen when migrating from older version and I have exported JSON file, which contains "realm-management" client but not "impersonation" client // Could happen when migrating from older version and I have exported JSON file, which contains "realm-management" client but not "impersonation" client
// I need to postpone impersonation because it needs "realm-management" client and it's roles set // I need to postpone impersonation because it needs "realm-management" client and it's roles set
if (postponeImpersonationSetup) { if (postponeImpersonationSetup) {
Expand All @@ -304,8 +354,16 @@ public RealmModel importRealm(RealmRepresentation rep) {
return realm; return realm;
} }


private boolean postponeMasterClientSetup(RealmRepresentation rep) {
if (!Config.getAdminRealm().equals(rep.getRealm())) {
return false;
}

return hasRealmAdminManagementClient(rep);
}

private boolean hasRealmAdminManagementClient(RealmRepresentation rep) { private boolean hasRealmAdminManagementClient(RealmRepresentation rep) {
String realmAdminClientId = getRealmAdminClientId(rep); String realmAdminClientId = Config.getAdminRealm().equals(rep.getRealm()) ? KeycloakModelUtils.getMasterRealmAdminApplicationClientId(rep.getRealm()) : getRealmAdminClientId(rep);
return hasClient(rep, realmAdminClientId); return hasClient(rep, realmAdminClientId);
} }


Expand Down
Expand Up @@ -77,7 +77,7 @@ public void config(RealmManager manager, RealmModel adminstrationRealm, RealmMod
{ {
UserModel masterImpersonator = manager.getSession().users().addUser(adminstrationRealm, "master-impersonator"); UserModel masterImpersonator = manager.getSession().users().addUser(adminstrationRealm, "master-impersonator");
masterImpersonator.setEnabled(true); masterImpersonator.setEnabled(true);
ClientModel adminRealmClient = adminstrationRealm.getClientByClientId(KeycloakModelUtils.getMasterRealmAdminApplicationClientId(appRealm)); ClientModel adminRealmClient = adminstrationRealm.getClientByClientId(KeycloakModelUtils.getMasterRealmAdminApplicationClientId(appRealm.getName()));
RoleModel masterImpersonatorRole = adminRealmClient.getRole(ImpersonationConstants.IMPERSONATION_ROLE); RoleModel masterImpersonatorRole = adminRealmClient.getRole(ImpersonationConstants.IMPERSONATION_ROLE);
masterImpersonator.grantRole(masterImpersonatorRole); masterImpersonator.grantRole(masterImpersonatorRole);
} }
Expand Down

0 comments on commit 5b9d128

Please sign in to comment.