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 ee4b561cc0..3653fc94fd 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 @@ -301,7 +301,7 @@ public class RepresentationToModel { String parentId = newRealm.getId(); importComponents(newRealm, components, parentId); } - importUserFederationProvidersAndMappers(rep, newRealm); + importUserFederationProvidersAndMappers(session, rep, newRealm); if (rep.getGroups() != null) { @@ -358,7 +358,7 @@ public class RepresentationToModel { } } - public static void importUserFederationProvidersAndMappers(RealmRepresentation rep, RealmModel newRealm) { + public static void importUserFederationProvidersAndMappers(KeycloakSession session, RealmRepresentation rep, RealmModel newRealm) { // providers to convert to component model Set convertSet = new HashSet<>(); convertSet.add(LDAPConstants.LDAP_PROVIDER); @@ -382,6 +382,10 @@ public class RepresentationToModel { } newRealm.setUserFederationProviders(providerModels); } + + // This is for case, when you have hand-written JSON file with LDAP userFederationProvider, but WITHOUT any userFederationMappers configured. Default LDAP mappers need to be created in that case. + Set storageProvidersWhichShouldImportDefaultMappers = new HashSet<>(userStorageModels.keySet()); + if (rep.getUserFederationMappers() != null) { // Remove builtin mappers for federation providers, which have some mappers already provided in JSON (likely due to previous export) @@ -409,11 +413,18 @@ public class RepresentationToModel { ComponentModel mapper = convertFedMapperToComponent(newRealm, parent, representation, newMapperType); newRealm.importComponentModel(mapper); + + storageProvidersWhichShouldImportDefaultMappers.remove(representation.getFederationProviderDisplayName()); + } else { newRealm.addUserFederationMapper(toModel(newRealm, representation)); } } } + + for (String providerDisplayName : storageProvidersWhichShouldImportDefaultMappers) { + ComponentUtil.notifyCreated(session, newRealm, userStorageModels.get(providerDisplayName)); + } } protected static void importComponents(RealmModel newRealm, MultivaluedHashMap components, String parentId) { diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPLegacyImportTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPLegacyImportTest.java index fc34c86007..9e26fcfe9f 100755 --- a/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPLegacyImportTest.java +++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/federation/storage/ldap/LDAPLegacyImportTest.java @@ -97,7 +97,7 @@ public class LDAPLegacyImportTest { } catch (IOException e) { throw new RuntimeException(e); } - RepresentationToModel.importUserFederationProvidersAndMappers(imported, appRealm); + RepresentationToModel.importUserFederationProvidersAndMappers(session, imported, appRealm); ldapModel = appRealm.getComponents(appRealm.getId(), UserStorageProvider.class.getName()).get(0); // Delete all LDAP users and add some new for testing LDAPStorageProvider ldapFedProvider = LDAPTestUtils.getLdapProvider(session, ldapModel); diff --git a/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js b/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js index 36b432fd7c..bf59be0f7e 100755 --- a/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js +++ b/themes/src/main/resources/theme/base/admin/resources/js/controllers/users.js @@ -1788,7 +1788,7 @@ module.controller('LDAPUserStorageCtrl', function($scope, $location, Notificatio $scope.save = function() { $scope.changed = false; - if (!parseInt($scope.instance.config['batchSizeForSync'][0])) { + if (!$scope.instance.config['batchSizeForSync'] || !parseInt($scope.instance.config['batchSizeForSync'][0])) { $scope.instance.config['batchSizeForSync'] = [ DEFAULT_BATCH_SIZE ]; } else { $scope.instance.config['batchSizeForSync'][0] = parseInt($scope.instance.config.batchSizeForSync).toString();