diff --git a/model/storage-private/src/main/java/org/keycloak/storage/UserStorageSyncTask.java b/model/storage-private/src/main/java/org/keycloak/storage/UserStorageSyncTask.java index 543d8f42237..f02737ead33 100644 --- a/model/storage-private/src/main/java/org/keycloak/storage/UserStorageSyncTask.java +++ b/model/storage-private/src/main/java/org/keycloak/storage/UserStorageSyncTask.java @@ -38,8 +38,18 @@ final class UserStorageSyncTask implements ScheduledTask { @Override public void run(KeycloakSession session) { RealmModel realm = session.realms().getRealm(realmId); + session.getContext().setRealm(realm); - runWithResult(session); + + UserStorageProviderModel provider = getStorageModel(session); + + if (isSyncPeriod(provider)) { + runWithResult(session); + return; + } + + logger.debugf("Ignored LDAP %s users-sync with storage provider %s due small time since last sync in realm %s", // + syncMode, provider.getName(), realmId); } @Override @@ -49,19 +59,10 @@ final class UserStorageSyncTask implements ScheduledTask { SynchronizationResult runWithResult(KeycloakSession session) { try { - UserStorageProviderModel provider = getStorageModel(session); - - if (isSyncPeriod(provider)) { - return switch (syncMode) { - case FULL -> runFullSync(session); - case CHANGED -> runIncrementalSync(session); - }; - } - - logger.debugf("Ignored LDAP %s users-sync with storage provider %s due small time since last sync in realm %s", // - syncMode, provider.getName(), realmId); - - return SynchronizationResult.ignored(); + return switch (syncMode) { + case FULL -> runFullSync(session); + case CHANGED -> runIncrementalSync(session); + }; } catch (Throwable t) { logger.errorf(t, "Error occurred during %s users-sync in realm %s and user provider %s", syncMode, realmId, providerId); } diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java index d12654551f4..0f197c01936 100644 --- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java +++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/federation/sync/SyncFederationTest.java @@ -132,8 +132,43 @@ public class SyncFederationTest extends AbstractAuthTest { }); } + @Test + public void testForceManualSync() { + // Enable timer for SyncDummyUserFederationProvider + testingClient.server().run(session -> { + RealmModel appRealm = session.realms().getRealmByName(AuthRealm.TEST); + UserStorageProviderModel model = new UserStorageProviderModel(); - private static final UserStorageProviderModel findDummyProviderModel(RealmModel realm) { + model.setProviderId(DummyUserFederationProviderFactory.PROVIDER_NAME); + model.setPriority(1); + model.setName("test-sync-dummy"); + model.setFullSyncPeriod(1); + model.setLastSync(0); + + appRealm.addComponentModel(model); + }); + + testingClient.server().run(session -> { + RealmModel appRealm = session.realms().getRealmByName(AuthRealm.TEST); + UserStorageProviderModel dummyModel = findDummyProviderModel(appRealm); + KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory(); + + sleep(dummyModel.getFullSyncPeriod() * 2L); + session.getContext().setRealm(appRealm); + SynchronizationResult result = UserStoragePrivateUtil.runFullSync(sessionFactory, dummyModel); + Assert.assertFalse(result.isIgnored()); + }); + + // remove dummyProvider + testingClient.server().run(session -> { + RealmModel appRealm = session.realms().getRealmByName(AuthRealm.TEST); + session.getContext().setRealm(appRealm); + UserStorageProviderModel dummyModel = findDummyProviderModel(appRealm); + appRealm.removeComponent(dummyModel); + }); + } + + private static UserStorageProviderModel findDummyProviderModel(RealmModel realm) { return realm.getComponentsStream() .filter(component -> Objects.equals(component.getName(), "test-sync-dummy")) .map(UserStorageProviderModel::new)