Search in sources :

Example 21 with SynchronizationResult

use of org.keycloak.storage.user.SynchronizationResult in project keycloak by keycloak.

the class LDAPStorageProviderFactory method syncSince.

@Override
public SynchronizationResult syncSince(Date lastSync, KeycloakSessionFactory sessionFactory, String realmId, UserStorageProviderModel model) {
    syncMappers(sessionFactory, realmId, model);
    logger.infof("Sync changed users from LDAP to local store: realm: %s, federation provider: %s, last sync time: " + lastSync, realmId, model.getName());
    // Sync newly created and updated users
    LDAPQueryConditionsBuilder conditionsBuilder = new LDAPQueryConditionsBuilder();
    Condition createCondition = conditionsBuilder.greaterThanOrEqualTo(LDAPConstants.CREATE_TIMESTAMP, lastSync);
    Condition modifyCondition = conditionsBuilder.greaterThanOrEqualTo(LDAPConstants.MODIFY_TIMESTAMP, lastSync);
    Condition orCondition = conditionsBuilder.orCondition(createCondition, modifyCondition);
    try (LDAPQuery userQuery = createQuery(sessionFactory, realmId, model)) {
        userQuery.addWhereCondition(orCondition);
        SynchronizationResult result = syncImpl(sessionFactory, userQuery, realmId, model);
        logger.infof("Sync changed users finished: %s", result.getStatus());
        return result;
    }
}
Also used : Condition(org.keycloak.storage.ldap.idm.query.Condition) LDAPQuery(org.keycloak.storage.ldap.idm.query.internal.LDAPQuery) SynchronizationResult(org.keycloak.storage.user.SynchronizationResult) LDAPQueryConditionsBuilder(org.keycloak.storage.ldap.idm.query.internal.LDAPQueryConditionsBuilder)

Example 22 with SynchronizationResult

use of org.keycloak.storage.user.SynchronizationResult in project keycloak by keycloak.

the class LDAPStorageProviderFactory method importLdapUsers.

protected SynchronizationResult importLdapUsers(KeycloakSessionFactory sessionFactory, final String realmId, final ComponentModel fedModel, List<LDAPObject> ldapUsers) {
    final SynchronizationResult syncResult = new SynchronizationResult();
    class BooleanHolder {

        private boolean value = true;
    }
    final BooleanHolder exists = new BooleanHolder();
    for (final LDAPObject ldapUser : ldapUsers) {
        try {
            // Process each user in it's own transaction to avoid global fail
            KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {

                @Override
                public void run(KeycloakSession session) {
                    LDAPStorageProvider ldapFedProvider = (LDAPStorageProvider) session.getProvider(UserStorageProvider.class, fedModel);
                    RealmModel currentRealm = session.realms().getRealm(realmId);
                    session.getContext().setRealm(currentRealm);
                    String username = LDAPUtils.getUsername(ldapUser, ldapFedProvider.getLdapIdentityStore().getConfig());
                    exists.value = true;
                    LDAPUtils.checkUuid(ldapUser, ldapFedProvider.getLdapIdentityStore().getConfig());
                    UserModel currentUserLocal = session.userLocalStorage().getUserByUsername(currentRealm, username);
                    Optional<UserModel> userModelOptional = session.userLocalStorage().searchForUserByUserAttributeStream(currentRealm, LDAPConstants.LDAP_ID, ldapUser.getUuid()).findFirst();
                    if (!userModelOptional.isPresent() && currentUserLocal == null) {
                        // Add new user to Keycloak
                        exists.value = false;
                        ldapFedProvider.importUserFromLDAP(session, currentRealm, ldapUser);
                        syncResult.increaseAdded();
                    } else {
                        UserModel currentUser = userModelOptional.isPresent() ? userModelOptional.get() : currentUserLocal;
                        if ((fedModel.getId().equals(currentUser.getFederationLink())) && (ldapUser.getUuid().equals(currentUser.getFirstAttribute(LDAPConstants.LDAP_ID)))) {
                            // Update keycloak user
                            LDAPMappersComparator ldapMappersComparator = new LDAPMappersComparator(ldapFedProvider.getLdapIdentityStore().getConfig());
                            currentRealm.getComponentsStream(fedModel.getId(), LDAPStorageMapper.class.getName()).sorted(ldapMappersComparator.sortDesc()).forEachOrdered(mapperModel -> {
                                LDAPStorageMapper ldapMapper = ldapFedProvider.getMapperManager().getMapper(mapperModel);
                                ldapMapper.onImportUserFromLDAP(ldapUser, currentUser, currentRealm, false);
                            });
                            UserCache userCache = session.userCache();
                            if (userCache != null) {
                                userCache.evict(currentRealm, currentUser);
                            }
                            logger.debugf("Updated user from LDAP: %s", currentUser.getUsername());
                            syncResult.increaseUpdated();
                        } else {
                            logger.warnf("User with ID '%s' is not updated during sync as he already exists in Keycloak database but is not linked to federation provider '%s'", ldapUser.getUuid(), fedModel.getName());
                            syncResult.increaseFailed();
                        }
                    }
                }
            });
        } catch (ModelException me) {
            logger.error("Failed during import user from LDAP", me);
            syncResult.increaseFailed();
            // Remove user if we already added him during this transaction
            if (!exists.value) {
                KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {

                    @Override
                    public void run(KeycloakSession session) {
                        LDAPStorageProvider ldapFedProvider = (LDAPStorageProvider) session.getProvider(UserStorageProvider.class, fedModel);
                        RealmModel currentRealm = session.realms().getRealm(realmId);
                        session.getContext().setRealm(currentRealm);
                        String username = null;
                        try {
                            username = LDAPUtils.getUsername(ldapUser, ldapFedProvider.getLdapIdentityStore().getConfig());
                        } catch (ModelException ignore) {
                        }
                        if (username != null) {
                            UserModel existing = session.userLocalStorage().getUserByUsername(currentRealm, username);
                            if (existing != null) {
                                UserCache userCache = session.userCache();
                                if (userCache != null) {
                                    userCache.evict(currentRealm, existing);
                                }
                                session.userLocalStorage().removeUser(currentRealm, existing);
                            }
                        }
                    }
                });
            }
        }
    }
    return syncResult;
}
Also used : SPNEGOAuthenticator(org.keycloak.federation.kerberos.impl.SPNEGOAuthenticator) FullNameLDAPStorageMapperFactory(org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapperFactory) Date(java.util.Date) LDAPStorageMapper(org.keycloak.storage.ldap.mappers.LDAPStorageMapper) Config(org.keycloak.Config) FullNameLDAPStorageMapper(org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapper) ProviderConfigurationBuilder(org.keycloak.provider.ProviderConfigurationBuilder) LDAPConstants(org.keycloak.models.LDAPConstants) Map(java.util.Map) ComponentModel(org.keycloak.component.ComponentModel) CredentialRepresentation(org.keycloak.representations.idm.CredentialRepresentation) UserStorageProviderModel(org.keycloak.storage.UserStorageProviderModel) UserAttributeLDAPStorageMapperFactory(org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapperFactory) UserStorageProviderFactory(org.keycloak.storage.UserStorageProviderFactory) HardcodedLDAPAttributeMapper(org.keycloak.storage.ldap.mappers.HardcodedLDAPAttributeMapper) HardcodedLDAPAttributeMapperFactory(org.keycloak.storage.ldap.mappers.HardcodedLDAPAttributeMapperFactory) RealmModel(org.keycloak.models.RealmModel) LDAPConfigDecorator(org.keycloak.storage.ldap.mappers.LDAPConfigDecorator) CredentialHelper(org.keycloak.utils.CredentialHelper) CommonKerberosConfig(org.keycloak.federation.kerberos.CommonKerberosConfig) Collectors(java.util.stream.Collectors) LDAPObject(org.keycloak.storage.ldap.idm.model.LDAPObject) ImportSynchronization(org.keycloak.storage.user.ImportSynchronization) List(java.util.List) UserAttributeLDAPStorageMapper(org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapper) KerberosUsernamePasswordAuthenticator(org.keycloak.federation.kerberos.impl.KerberosUsernamePasswordAuthenticator) KeycloakSessionFactory(org.keycloak.models.KeycloakSessionFactory) Optional(java.util.Optional) Condition(org.keycloak.storage.ldap.idm.query.Condition) ComponentValidationException(org.keycloak.component.ComponentValidationException) KeycloakModelUtils(org.keycloak.models.utils.KeycloakModelUtils) Logger(org.jboss.logging.Logger) ProviderConfigProperty(org.keycloak.provider.ProviderConfigProperty) Function(java.util.function.Function) LDAPIdentityStore(org.keycloak.storage.ldap.idm.store.ldap.LDAPIdentityStore) UserModel(org.keycloak.models.UserModel) AuthenticationExecutionModel(org.keycloak.models.AuthenticationExecutionModel) KeycloakSessionTask(org.keycloak.models.KeycloakSessionTask) LDAPQueryConditionsBuilder(org.keycloak.storage.ldap.idm.query.internal.LDAPQueryConditionsBuilder) KerberosConstants(org.keycloak.common.constants.KerberosConstants) UserStorageProvider(org.keycloak.storage.UserStorageProvider) LDAPMappersComparator(org.keycloak.storage.ldap.mappers.LDAPMappersComparator) KerberosServerSubjectAuthenticator(org.keycloak.federation.kerberos.impl.KerberosServerSubjectAuthenticator) KeycloakSession(org.keycloak.models.KeycloakSession) LDAPQuery(org.keycloak.storage.ldap.idm.query.internal.LDAPQuery) UserCache(org.keycloak.models.cache.UserCache) MSADUserAccountControlStorageMapperFactory(org.keycloak.storage.ldap.mappers.msad.MSADUserAccountControlStorageMapperFactory) ModelException(org.keycloak.models.ModelException) SynchronizationResult(org.keycloak.storage.user.SynchronizationResult) LDAPStorageMapper(org.keycloak.storage.ldap.mappers.LDAPStorageMapper) FullNameLDAPStorageMapper(org.keycloak.storage.ldap.mappers.FullNameLDAPStorageMapper) UserAttributeLDAPStorageMapper(org.keycloak.storage.ldap.mappers.UserAttributeLDAPStorageMapper) Optional(java.util.Optional) LDAPMappersComparator(org.keycloak.storage.ldap.mappers.LDAPMappersComparator) ModelException(org.keycloak.models.ModelException) UserCache(org.keycloak.models.cache.UserCache) RealmModel(org.keycloak.models.RealmModel) UserModel(org.keycloak.models.UserModel) UserStorageProvider(org.keycloak.storage.UserStorageProvider) KeycloakSessionTask(org.keycloak.models.KeycloakSessionTask) KeycloakSession(org.keycloak.models.KeycloakSession) LDAPObject(org.keycloak.storage.ldap.idm.model.LDAPObject) SynchronizationResult(org.keycloak.storage.user.SynchronizationResult)

Example 23 with SynchronizationResult

use of org.keycloak.storage.user.SynchronizationResult in project keycloak by keycloak.

the class GroupLDAPStorageMapper method syncDataFromKeycloakToFederationProvider.

// Sync from Keycloak to LDAP
@Override
public SynchronizationResult syncDataFromKeycloakToFederationProvider(RealmModel realm) {
    SynchronizationResult syncResult = new SynchronizationResult() {

        @Override
        public String getStatus() {
            return String.format("%d groups imported to LDAP, %d groups updated to LDAP, %d groups removed from LDAP", getAdded(), getUpdated(), getRemoved());
        }
    };
    if (config.getMode() != LDAPGroupMapperMode.LDAP_ONLY) {
        logger.warnf("Ignored sync for federation mapper '%s' as it's mode is '%s'", mapperModel.getName(), config.getMode().toString());
        return syncResult;
    }
    logger.debugf("Syncing groups from Keycloak into LDAP. Mapper is [%s], LDAP provider is [%s]", mapperModel.getName(), ldapProvider.getModel().getName());
    // Query existing LDAP groups
    List<LDAPObject> ldapGroups = getAllLDAPGroups(config.isPreserveGroupsInheritance());
    // Convert them to Map<String, LDAPObject>
    Map<String, LDAPObject> ldapGroupsMap = new HashMap<>();
    String groupsRdnAttr = config.getGroupNameLdapAttribute();
    for (LDAPObject ldapGroup : ldapGroups) {
        String groupName = ldapGroup.getAttributeAsString(groupsRdnAttr);
        ldapGroupsMap.put(groupName, ldapGroup);
    }
    // Map to track all LDAP groups also exist in Keycloak
    Set<String> ldapGroupNames = new HashSet<>();
    // Create or update KC groups to LDAP including their attributes
    getKcSubGroups(realm, null).forEach(kcGroup -> processKeycloakGroupSyncToLDAP(kcGroup, ldapGroupsMap, ldapGroupNames, syncResult));
    // If dropNonExisting, then drop all groups, which doesn't exist in KC from LDAP as well
    if (config.isDropNonExistingGroupsDuringSync()) {
        Set<String> copy = new HashSet<>(ldapGroupsMap.keySet());
        for (String groupName : copy) {
            if (!ldapGroupNames.contains(groupName)) {
                LDAPObject ldapGroup = ldapGroupsMap.remove(groupName);
                ldapProvider.getLdapIdentityStore().remove(ldapGroup);
                syncResult.increaseRemoved();
            }
        }
    }
    // Finally process memberships,
    if (config.isPreserveGroupsInheritance()) {
        getKcSubGroups(realm, null).forEach(kcGroup -> processKeycloakGroupMembershipsSyncToLDAP(kcGroup, ldapGroupsMap));
    }
    return syncResult;
}
Also used : HashMap(java.util.HashMap) LDAPObject(org.keycloak.storage.ldap.idm.model.LDAPObject) SynchronizationResult(org.keycloak.storage.user.SynchronizationResult) HashSet(java.util.HashSet)

Example 24 with SynchronizationResult

use of org.keycloak.storage.user.SynchronizationResult in project keycloak by keycloak.

the class SyncFederationTest method test03ConcurrentSync.

@Test
public void test03ConcurrentSync() throws Exception {
    // Enable timer for SyncDummyUserFederationProvider
    testingClient.server().run(session -> {
        SyncDummyUserFederationProviderFactory.restartLatches();
        RealmModel appRealm = session.realms().getRealmByName(AuthRealm.TEST);
        UserStorageProviderModel model = new UserStorageProviderModel();
        model.setProviderId(SyncDummyUserFederationProviderFactory.SYNC_PROVIDER_ID);
        model.setPriority(1);
        model.setName("test-sync-dummy");
        model.setFullSyncPeriod(-1);
        model.setChangedSyncPeriod(1);
        model.setLastSync(0);
        model.getConfig().putSingle(SyncDummyUserFederationProviderFactory.WAIT_TIME, "2000");
        ComponentModel dummyModel = new UserStorageProviderModel(appRealm.addComponentModel(model));
    });
    testingClient.server().run(session -> {
        RealmModel appRealm = session.realms().getRealmByName(AuthRealm.TEST);
        UserStorageProviderModel dummyModel = findDummyProviderModel(appRealm);
        KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
        // bootstrap periodic sync
        UserStorageSyncManager usersSyncManager = new UserStorageSyncManager();
        usersSyncManager.bootstrapPeriodic(sessionFactory, session.getProvider(TimerProvider.class));
        // Wait and then trigger sync manually. Assert it will be ignored
        sleep(1800);
        SynchronizationResult syncResult = usersSyncManager.syncChangedUsers(sessionFactory, appRealm.getId(), dummyModel);
        Assert.assertTrue(syncResult.isIgnored());
        // Cancel timer
        usersSyncManager.notifyToRefreshPeriodicSync(session, appRealm, dummyModel, true);
        // Signal to factory to finish waiting
        SyncDummyUserFederationProviderFactory.latch1.countDown();
        try {
            SyncDummyUserFederationProviderFactory.latch2.await(20000, TimeUnit.MILLISECONDS);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    });
    // remove provider
    testingClient.server().run(session -> {
        RealmModel appRealm = session.realms().getRealmByName(AuthRealm.TEST);
        UserStorageProviderModel dummyModel = findDummyProviderModel(appRealm);
        appRealm.removeComponent(dummyModel);
    });
}
Also used : RealmModel(org.keycloak.models.RealmModel) UserStorageSyncManager(org.keycloak.services.managers.UserStorageSyncManager) ComponentModel(org.keycloak.component.ComponentModel) TimerProvider(org.keycloak.timer.TimerProvider) UserStorageProviderModel(org.keycloak.storage.UserStorageProviderModel) SynchronizationResult(org.keycloak.storage.user.SynchronizationResult) KeycloakSessionFactory(org.keycloak.models.KeycloakSessionFactory) Test(org.junit.Test) AbstractAuthTest(org.keycloak.testsuite.AbstractAuthTest)

Example 25 with SynchronizationResult

use of org.keycloak.storage.user.SynchronizationResult in project keycloak by keycloak.

the class LDAPSyncTest method test05MissingLDAPUsernameSync.

// KEYCLOAK-1728
@Test
public void test05MissingLDAPUsernameSync() {
    String origUsernameAttrName = testingClient.server().fetch(session -> {
        LDAPTestContext ctx = LDAPTestContext.init(session);
        // Remove all users from model
        session.userLocalStorage().getUsersStream(ctx.getRealm(), true).peek(user -> System.out.println("trying to delete user: " + user.getUsername())).collect(Collectors.toList()).forEach(user -> {
            UserCache userCache = session.userCache();
            if (userCache != null) {
                userCache.evict(ctx.getRealm(), user);
            }
            session.userLocalStorage().removeUser(ctx.getRealm(), user);
        });
        // Add street mapper and add some user including street
        ComponentModel streetMapper = LDAPTestUtils.addUserAttributeMapper(ctx.getRealm(), ctx.getLdapModel(), "streetMapper", "street", LDAPConstants.STREET);
        LDAPObject streetUser = LDAPTestUtils.addLDAPUser(ctx.getLdapProvider(), ctx.getRealm(), "user8", "User8FN", "User8LN", "user8@email.org", "user8street", "126");
        // Change name of username attribute name to street
        String origUsernameAttrNamee = ctx.getLdapModel().get(LDAPConstants.USERNAME_LDAP_ATTRIBUTE);
        ctx.getLdapModel().getConfig().putSingle(LDAPConstants.USERNAME_LDAP_ATTRIBUTE, "street");
        // Need to change this due to ApacheDS pagination bug (For other LDAP servers, pagination works fine) TODO: Remove once ApacheDS upgraded and pagination is fixed
        ctx.getLdapModel().put(LDAPConstants.BATCH_SIZE_FOR_SYNC, "10");
        ctx.getRealm().updateComponent(ctx.getLdapModel());
        return origUsernameAttrNamee;
    }, String.class);
    // Just user8 synced. All others failed to sync
    testingClient.server().run(session -> {
        LDAPTestContext ctx = LDAPTestContext.init(session);
        KeycloakSessionFactory sessionFactory = session.getKeycloakSessionFactory();
        SynchronizationResult syncResult = new UserStorageSyncManager().syncAllUsers(sessionFactory, "test", ctx.getLdapModel());
        Assert.assertEquals(1, syncResult.getAdded());
        Assert.assertTrue(syncResult.getFailed() > 0);
    });
    // Revert config changes
    ComponentRepresentation ldapRep = testRealm().components().component(ldapModelId).toRepresentation();
    if (origUsernameAttrName == null) {
        ldapRep.getConfig().remove(LDAPConstants.USERNAME_LDAP_ATTRIBUTE);
    } else {
        ldapRep.getConfig().putSingle(LDAPConstants.USERNAME_LDAP_ATTRIBUTE, origUsernameAttrName);
    }
    testRealm().components().component(ldapModelId).update(ldapRep);
    testingClient.server().run(session -> {
        LDAPTestContext ctx = LDAPTestContext.init(session);
        // Revert config changes
        ComponentModel streetMapper = LDAPTestUtils.getSubcomponentByName(ctx.getRealm(), ctx.getLdapModel(), "streetMapper");
        ctx.getRealm().removeComponent(streetMapper);
    });
}
Also used : ComponentRepresentation(org.keycloak.representations.idm.ComponentRepresentation) UserStorageSyncManager(org.keycloak.services.managers.UserStorageSyncManager) ComponentModel(org.keycloak.component.ComponentModel) LDAPObject(org.keycloak.storage.ldap.idm.model.LDAPObject) SynchronizationResult(org.keycloak.storage.user.SynchronizationResult) UserCache(org.keycloak.models.cache.UserCache) KeycloakSessionFactory(org.keycloak.models.KeycloakSessionFactory) Test(org.junit.Test)

Aggregations

SynchronizationResult (org.keycloak.storage.user.SynchronizationResult)33 RealmModel (org.keycloak.models.RealmModel)20 Test (org.junit.Test)18 ComponentModel (org.keycloak.component.ComponentModel)18 LDAPObject (org.keycloak.storage.ldap.idm.model.LDAPObject)16 UserStorageSyncManager (org.keycloak.services.managers.UserStorageSyncManager)12 LDAPStorageProvider (org.keycloak.storage.ldap.LDAPStorageProvider)11 GroupModel (org.keycloak.models.GroupModel)9 KeycloakSessionFactory (org.keycloak.models.KeycloakSessionFactory)9 GroupLDAPStorageMapperFactory (org.keycloak.storage.ldap.mappers.membership.group.GroupLDAPStorageMapperFactory)9 HashMap (java.util.HashMap)8 UserModel (org.keycloak.models.UserModel)7 UserStorageProvider (org.keycloak.storage.UserStorageProvider)7 UserStorageProviderModel (org.keycloak.storage.UserStorageProviderModel)7 KeycloakSession (org.keycloak.models.KeycloakSession)5 LDAPQuery (org.keycloak.storage.ldap.idm.query.internal.LDAPQuery)5 KeycloakSessionTask (org.keycloak.models.KeycloakSessionTask)4 UserStorageProviderFactory (org.keycloak.storage.UserStorageProviderFactory)4 ImportSynchronization (org.keycloak.storage.user.ImportSynchronization)4 List (java.util.List)3