diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/RealmImporter.java b/server-spi-private/src/main/java/org/keycloak/models/utils/RealmImporter.java
deleted file mode 100644
index e2c34011e3..0000000000
--- a/server-spi-private/src/main/java/org/keycloak/models/utils/RealmImporter.java
+++ /dev/null
@@ -1,31 +0,0 @@
-/*
- * Copyright 2016 Red Hat, Inc. and/or its affiliates
- * and other contributors as indicated by the @author tags.
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- * http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-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 Marek Posolda
- */
-public interface RealmImporter {
-
- RealmModel importRealm(RealmRepresentation rep);
-}
diff --git a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
index a21d545136..e3e3557704 100755
--- a/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
+++ b/server-spi-private/src/main/java/org/keycloak/models/utils/RepresentationToModel.java
@@ -129,7 +129,7 @@ public class RepresentationToModel {
return policy;
}
- public static void importRealm(KeycloakSession session, RealmRepresentation rep, RealmModel newRealm) {
+ public static void importRealm(KeycloakSession session, RealmRepresentation rep, RealmModel newRealm, boolean skipUserDependent) {
convertDeprecatedSocialProviders(rep);
convertDeprecatedApplications(session, rep);
@@ -279,13 +279,6 @@ public class RepresentationToModel {
}
}
- if (rep.getClients() != null) {
- rep.getClients().forEach(clientRepresentation -> {
- ClientModel client = newRealm.getClientByClientId(clientRepresentation.getClientId());
- importAuthorizationSettings(clientRepresentation, client, session);
- });
- }
-
if (rep.getSmtpServer() != null) {
newRealm.setSmtpConfig(new HashMap(rep.getSmtpServer()));
}
@@ -331,6 +324,10 @@ public class RepresentationToModel {
}
}
+ if (!skipUserDependent) {
+ importRealmAuthorizationSettings(rep, newRealm, session);
+ }
+
if(rep.isInternationalizationEnabled() != null){
newRealm.setInternationalizationEnabled(rep.isInternationalizationEnabled());
}
@@ -1813,6 +1810,15 @@ public class RepresentationToModel {
}
}
+ public static void importRealmAuthorizationSettings(RealmRepresentation rep, RealmModel newRealm, KeycloakSession session) {
+ if (rep.getClients() != null) {
+ rep.getClients().forEach(clientRepresentation -> {
+ ClientModel client = newRealm.getClientByClientId(clientRepresentation.getClientId());
+ importAuthorizationSettings(clientRepresentation, client, session);
+ });
+ }
+ }
+
public static void importAuthorizationSettings(ClientRepresentation clientRepresentation, ClientModel client, KeycloakSession session) {
if (Boolean.TRUE.equals(clientRepresentation.getAuthorizationServicesEnabled())) {
AuthorizationProviderFactory authorizationFactory = (AuthorizationProviderFactory) session.getKeycloakSessionFactory().getProviderFactory(AuthorizationProvider.class);
diff --git a/services/src/main/java/org/keycloak/exportimport/dir/DirImportProvider.java b/services/src/main/java/org/keycloak/exportimport/dir/DirImportProvider.java
index e31cb8efc1..a2a0699c72 100755
--- a/services/src/main/java/org/keycloak/exportimport/dir/DirImportProvider.java
+++ b/services/src/main/java/org/keycloak/exportimport/dir/DirImportProvider.java
@@ -25,7 +25,9 @@ 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.RealmModel;
import org.keycloak.models.utils.KeycloakModelUtils;
+import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.util.JsonSerialization;
@@ -136,7 +138,7 @@ public class DirImportProvider implements ImportProvider {
@Override
public void runExportImportTask(KeycloakSession session) throws IOException {
- boolean imported = ImportUtils.importRealm(session, realmRep, strategy);
+ boolean imported = ImportUtils.importRealm(session, realmRep, strategy, true);
realmImported.set(imported);
}
@@ -165,6 +167,17 @@ public class DirImportProvider implements ImportProvider {
});
}
}
+
+ // Import authorization last, as authzPolicies can require users already in DB
+ KeycloakModelUtils.runJobInTransaction(factory, new ExportImportSessionTask() {
+
+ @Override
+ public void runExportImportTask(KeycloakSession session) throws IOException {
+ RealmModel realm = session.realms().getRealmByName(realmName);
+ RepresentationToModel.importRealmAuthorizationSettings(realmRep, realm, session);
+ }
+
+ });
}
@Override
diff --git a/services/src/main/java/org/keycloak/exportimport/singlefile/SingleFileImportProviderFactory.java b/services/src/main/java/org/keycloak/exportimport/singlefile/SingleFileImportProviderFactory.java
index 5b486c900b..a54af3fa90 100755
--- a/services/src/main/java/org/keycloak/exportimport/singlefile/SingleFileImportProviderFactory.java
+++ b/services/src/main/java/org/keycloak/exportimport/singlefile/SingleFileImportProviderFactory.java
@@ -34,6 +34,9 @@ public class SingleFileImportProviderFactory implements ImportProviderFactory {
@Override
public ImportProvider create(KeycloakSession session) {
String fileName = ExportImportConfig.getFile();
+ if (fileName == null) {
+ throw new IllegalArgumentException("Property " + ExportImportConfig.FILE + " needs to be provided!");
+ }
return new SingleFileImportProvider(new File(fileName));
}
diff --git a/services/src/main/java/org/keycloak/exportimport/util/ImportUtils.java b/services/src/main/java/org/keycloak/exportimport/util/ImportUtils.java
index 2357a65df9..0996c9cd54 100755
--- a/services/src/main/java/org/keycloak/exportimport/util/ImportUtils.java
+++ b/services/src/main/java/org/keycloak/exportimport/util/ImportUtils.java
@@ -28,7 +28,6 @@ import org.keycloak.exportimport.Strategy;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.RealmProvider;
-import org.keycloak.models.utils.RealmImporter;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.representations.idm.RealmRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
@@ -55,7 +54,7 @@ public class ImportUtils {
// Import admin realm first
for (RealmRepresentation realm : realms) {
if (Config.getAdminRealm().equals(realm.getRealm())) {
- if (importRealm(session, realm, strategy)) {
+ if (importRealm(session, realm, strategy, false)) {
masterImported = true;
}
}
@@ -63,7 +62,7 @@ public class ImportUtils {
for (RealmRepresentation realm : realms) {
if (!Config.getAdminRealm().equals(realm.getRealm())) {
- importRealm(session, realm, strategy);
+ importRealm(session, realm, strategy, false);
}
}
@@ -84,9 +83,10 @@ public class ImportUtils {
* @param session
* @param rep
* @param strategy specifies whether to overwrite or ignore existing realm or user entries
+ * @param skipUserDependent If true, then import of any models, which needs users already imported in DB, will be skipped. For example authorization
* @return newly imported realm (or existing realm if ignoreExisting is true and realm of this name already exists)
*/
- public static boolean importRealm(KeycloakSession session, RealmRepresentation rep, Strategy strategy) {
+ public static boolean importRealm(KeycloakSession session, RealmRepresentation rep, Strategy strategy, boolean skipUserDependent) {
String realmName = rep.getRealm();
RealmProvider model = session.realms();
RealmModel realm = model.getRealmByName(realmName);
@@ -110,7 +110,7 @@ public class ImportUtils {
RealmManager realmManager = new RealmManager(session);
realmManager.setContextPath(session.getContext().getContextPath());
- realmManager.importRealm(rep);
+ realmManager.importRealm(rep, skipUserDependent);
if (System.getProperty(ExportImportConfig.ACTION) != null) {
logger.infof("Realm '%s' imported", realmName);
diff --git a/services/src/main/java/org/keycloak/services/DefaultKeycloakContext.java b/services/src/main/java/org/keycloak/services/DefaultKeycloakContext.java
index 07313d87ba..e1e0880fca 100755
--- a/services/src/main/java/org/keycloak/services/DefaultKeycloakContext.java
+++ b/services/src/main/java/org/keycloak/services/DefaultKeycloakContext.java
@@ -24,8 +24,6 @@ import org.keycloak.models.KeycloakContext;
import org.keycloak.models.KeycloakSession;
import org.keycloak.models.RealmModel;
import org.keycloak.models.UserModel;
-import org.keycloak.models.utils.RealmImporter;
-import org.keycloak.services.managers.RealmManager;
import org.keycloak.services.resources.KeycloakApplication;
import org.keycloak.services.util.LocaleHelper;
diff --git a/services/src/main/java/org/keycloak/services/managers/RealmManager.java b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
index c6476234fe..cb80590b3b 100755
--- a/services/src/main/java/org/keycloak/services/managers/RealmManager.java
+++ b/services/src/main/java/org/keycloak/services/managers/RealmManager.java
@@ -37,7 +37,6 @@ import org.keycloak.models.session.UserSessionPersisterProvider;
import org.keycloak.models.utils.DefaultAuthenticationFlows;
import org.keycloak.models.utils.DefaultRequiredActions;
import org.keycloak.models.utils.KeycloakModelUtils;
-import org.keycloak.models.utils.RealmImporter;
import org.keycloak.models.utils.RepresentationToModel;
import org.keycloak.protocol.ProtocolMapperUtils;
import org.keycloak.protocol.oidc.OIDCLoginProtocol;
@@ -61,7 +60,7 @@ import java.util.List;
* @author Bill Burke
* @version $Revision: 1 $
*/
-public class RealmManager implements RealmImporter {
+public class RealmManager {
protected KeycloakSession session;
protected RealmProvider model;
@@ -420,8 +419,15 @@ public class RealmManager implements RealmImporter {
}
}
- @Override
public RealmModel importRealm(RealmRepresentation rep) {
+ return importRealm(rep, false);
+ }
+
+
+ /**
+ * if "skipUserDependent" is true, then import of any models, which needs users already imported in DB, will be skipped. For example authorization
+ */
+ public RealmModel importRealm(RealmRepresentation rep, boolean skipUserDependent) {
String id = rep.getId();
if (id == null) {
id = KeycloakModelUtils.generateId();
@@ -463,7 +469,7 @@ public class RealmManager implements RealmImporter {
if (!hasRealmRole(rep, Constants.OFFLINE_ACCESS_ROLE)) setupOfflineTokens(realm);
- RepresentationToModel.importRealm(session, rep, realm);
+ RepresentationToModel.importRealm(session, rep, realm, skipUserDependent);
setupAdminConsoleLocaleMapper(realm);
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java
index 3c296a12cf..f923cf4ac2 100644
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/exportimport/ExportImportUtil.java
@@ -627,11 +627,12 @@ public class ExportImportUtil {
assertPredicate(scopes, scopePredicates);
List policies = authzResource.policies().policies();
- Assert.assertEquals(10, policies.size());
+ Assert.assertEquals(11, policies.size());
List> policyPredicates = new ArrayList<>();
policyPredicates.add(policyRepresentation -> "Any Admin Policy".equals(policyRepresentation.getName()));
policyPredicates.add(policyRepresentation -> "Any User Policy".equals(policyRepresentation.getName()));
policyPredicates.add(policyRepresentation -> "Only Premium User Policy".equals(policyRepresentation.getName()));
+ policyPredicates.add(policyRepresentation -> "wburke policy".equals(policyRepresentation.getName()));
policyPredicates.add(policyRepresentation -> "All Users Policy".equals(policyRepresentation.getName()));
policyPredicates.add(policyRepresentation -> "Premium Resource Permission".equals(policyRepresentation.getName()));
policyPredicates.add(policyRepresentation -> "Administrative Resource Permission".equals(policyRepresentation.getName()));
diff --git a/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm.json b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm.json
index 6cd3ef6256..b540ab1bdb 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm.json
+++ b/testsuite/integration-arquillian/tests/base/src/test/resources/model/testrealm.json
@@ -291,6 +291,15 @@
"roles": "[{\"id\":\"customer-user-premium\"}]"
}
},
+ {
+ "name": "wburke policy",
+ "description": "Defines that only wburke can do something",
+ "type": "user",
+ "logic": "POSITIVE",
+ "config": {
+ "users" : "[\"wburke\"]"
+ }
+ },
{
"name": "All Users Policy",
"description": "Defines that all users can do something",