Search in sources :

Example 26 with SynchronizationResult

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

the class LDAPSyncTest method test08LDAPGroupSyncAfterGroupRename.

@Test
public void test08LDAPGroupSyncAfterGroupRename() {
    testingClient.server().run(session -> {
        LDAPTestContext ctx = LDAPTestContext.init(session);
        RealmModel appRealm = ctx.getRealm();
        String descriptionAttrName = LDAPTestUtils.getGroupDescriptionLDAPAttrName(ctx.getLdapProvider());
        // Add group mapper
        LDAPTestUtils.addOrUpdateGroupMapper(appRealm, ctx.getLdapModel(), LDAPGroupMapperMode.READ_ONLY, descriptionAttrName);
        LDAPObject group1 = LDAPTestUtils.createLDAPGroup(session, appRealm, ctx.getLdapModel(), "group1", descriptionAttrName, "group1 - description");
        LDAPObject group2 = LDAPTestUtils.createLDAPGroup(session, appRealm, ctx.getLdapModel(), "group2", descriptionAttrName, "group2 - description");
        LDAPUtils.addMember(ctx.getLdapProvider(), MembershipType.DN, LDAPConstants.MEMBER, "not-used", group2, group1);
        ComponentModel mapperModel = LDAPTestUtils.getSubcomponentByName(appRealm, ctx.getLdapModel(), "groupsMapper");
        LDAPTestUtils.updateGroupMapperConfigOptions(mapperModel, GroupMapperConfig.PRESERVE_GROUP_INHERITANCE, "false");
        ctx.getRealm().updateComponent(mapperModel);
        // sync groups to Keycloak
        new GroupLDAPStorageMapperFactory().create(session, mapperModel).syncDataFromFederationProviderToKeycloak(appRealm);
    });
    testingClient.server().run(session -> {
        LDAPTestContext ctx = LDAPTestContext.init(session);
        RealmModel appRealm = ctx.getRealm();
        GroupModel kcGroup1 = KeycloakModelUtils.findGroupByPath(appRealm, "/group1");
        String descriptionAttrName = LDAPTestUtils.getGroupDescriptionLDAPAttrName(ctx.getLdapProvider());
        Assert.assertEquals("group1 - description", kcGroup1.getFirstAttribute(descriptionAttrName));
    });
    testingClient.server().run(session -> {
        LDAPTestContext ctx = LDAPTestContext.init(session);
        RealmModel appRealm = ctx.getRealm();
        String descriptionAttrName = LDAPTestUtils.getGroupDescriptionLDAPAttrName(ctx.getLdapProvider());
        // Add group mapper
        LDAPTestUtils.addOrUpdateGroupMapper(appRealm, ctx.getLdapModel(), LDAPGroupMapperMode.LDAP_ONLY, descriptionAttrName);
        ComponentModel mapperModel = LDAPTestUtils.getSubcomponentByName(appRealm, ctx.getLdapModel(), "groupsMapper");
        LDAPStorageProvider ldapProvider = LDAPTestUtils.getLdapProvider(session, ctx.getLdapModel());
        GroupLDAPStorageMapper groupMapper = LDAPTestUtils.getGroupMapper(mapperModel, ldapProvider, appRealm);
        LDAPObject group1Loaded = groupMapper.loadLDAPGroupByName("group1");
        // update group name and description
        group1Loaded.setSingleAttribute(group1Loaded.getRdnAttributeNames().get(0), "group5");
        group1Loaded.setSingleAttribute(descriptionAttrName, "group5 - description");
        LDAPTestUtils.updateLDAPGroup(session, appRealm, ctx.getLdapModel(), group1Loaded);
        // sync to Keycloak should pass without an error
        SynchronizationResult syncResult = new GroupLDAPStorageMapperFactory().create(session, mapperModel).syncDataFromFederationProviderToKeycloak(appRealm);
        Assert.assertThat(syncResult.getFailed(), Matchers.is(0));
    });
    testingClient.server().run(session -> {
        LDAPTestContext ctx = LDAPTestContext.init(session);
        RealmModel appRealm = ctx.getRealm();
        // load previously synced group (a new group has been created in Keycloak)
        GroupModel kcGroup5 = KeycloakModelUtils.findGroupByPath(appRealm, "/group5");
        String descriptionAttrName = LDAPTestUtils.getGroupDescriptionLDAPAttrName(ctx.getLdapProvider());
        Assert.assertEquals("group5 - description", kcGroup5.getFirstAttribute(descriptionAttrName));
    });
}
Also used : RealmModel(org.keycloak.models.RealmModel) ComponentModel(org.keycloak.component.ComponentModel) LDAPObject(org.keycloak.storage.ldap.idm.model.LDAPObject) GroupModel(org.keycloak.models.GroupModel) LDAPStorageProvider(org.keycloak.storage.ldap.LDAPStorageProvider) GroupLDAPStorageMapperFactory(org.keycloak.storage.ldap.mappers.membership.group.GroupLDAPStorageMapperFactory) SynchronizationResult(org.keycloak.storage.user.SynchronizationResult) GroupLDAPStorageMapper(org.keycloak.storage.ldap.mappers.membership.group.GroupLDAPStorageMapper) Test(org.junit.Test)

Example 27 with SynchronizationResult

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

the class UserStorageSyncManager method syncChangedUsers.

public SynchronizationResult syncChangedUsers(final KeycloakSessionFactory sessionFactory, final String realmId, final UserStorageProviderModel provider) {
    UserStorageProviderFactory factory = (UserStorageProviderFactory) sessionFactory.getProviderFactory(UserStorageProvider.class, provider.getProviderId());
    if (!(factory instanceof ImportSynchronization) || !provider.isImportEnabled() || !provider.isEnabled()) {
        return SynchronizationResult.ignored();
    }
    final Holder holder = new Holder();
    // Ensure not executed concurrently on this or any other cluster node
    KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {

        @Override
        public void run(KeycloakSession session) {
            ClusterProvider clusterProvider = session.getProvider(ClusterProvider.class);
            // shared key for "full" and "changed" . Improve if needed
            String taskKey = provider.getId() + "::sync";
            // 30 seconds minimal timeout for now
            int timeout = Math.max(30, provider.getChangedSyncPeriod());
            holder.result = clusterProvider.executeIfNotExecuted(taskKey, timeout, new Callable<SynchronizationResult>() {

                @Override
                public SynchronizationResult call() throws Exception {
                    // See when we did last sync.
                    int oldLastSync = provider.getLastSync();
                    updateLastSyncInterval(sessionFactory, provider, realmId);
                    return ((ImportSynchronization) factory).syncSince(Time.toDate(oldLastSync), sessionFactory, realmId, provider);
                }
            });
        }
    });
    if (holder.result == null || !holder.result.isExecuted()) {
        logger.debugf("syncChangedUsers for federation provider %s was ignored as it's already in progress", provider.getName());
        return SynchronizationResult.ignored();
    } else {
        return holder.result.getResult();
    }
}
Also used : UserStorageProvider(org.keycloak.storage.UserStorageProvider) ClusterProvider(org.keycloak.cluster.ClusterProvider) KeycloakSessionTask(org.keycloak.models.KeycloakSessionTask) UserStorageProviderFactory(org.keycloak.storage.UserStorageProviderFactory) ImportSynchronization(org.keycloak.storage.user.ImportSynchronization) KeycloakSession(org.keycloak.models.KeycloakSession) SynchronizationResult(org.keycloak.storage.user.SynchronizationResult)

Example 28 with SynchronizationResult

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

the class UserStorageSyncManager method syncAllUsers.

public SynchronizationResult syncAllUsers(final KeycloakSessionFactory sessionFactory, final String realmId, final UserStorageProviderModel provider) {
    UserStorageProviderFactory factory = (UserStorageProviderFactory) sessionFactory.getProviderFactory(UserStorageProvider.class, provider.getProviderId());
    if (!(factory instanceof ImportSynchronization) || !provider.isImportEnabled() || !provider.isEnabled()) {
        return SynchronizationResult.ignored();
    }
    final Holder holder = new Holder();
    // Ensure not executed concurrently on this or any other cluster node
    KeycloakModelUtils.runJobInTransaction(sessionFactory, new KeycloakSessionTask() {

        @Override
        public void run(KeycloakSession session) {
            ClusterProvider clusterProvider = session.getProvider(ClusterProvider.class);
            // shared key for "full" and "changed" . Improve if needed
            String taskKey = provider.getId() + "::sync";
            // 30 seconds minimal timeout for now
            int timeout = Math.max(30, provider.getFullSyncPeriod());
            holder.result = clusterProvider.executeIfNotExecuted(taskKey, timeout, new Callable<SynchronizationResult>() {

                @Override
                public SynchronizationResult call() throws Exception {
                    updateLastSyncInterval(sessionFactory, provider, realmId);
                    return ((ImportSynchronization) factory).sync(sessionFactory, realmId, provider);
                }
            });
        }
    });
    if (holder.result == null || !holder.result.isExecuted()) {
        logger.debugf("syncAllUsers for federation provider %s was ignored as it's already in progress", provider.getName());
        return SynchronizationResult.ignored();
    } else {
        return holder.result.getResult();
    }
}
Also used : UserStorageProvider(org.keycloak.storage.UserStorageProvider) ClusterProvider(org.keycloak.cluster.ClusterProvider) KeycloakSessionTask(org.keycloak.models.KeycloakSessionTask) UserStorageProviderFactory(org.keycloak.storage.UserStorageProviderFactory) ImportSynchronization(org.keycloak.storage.user.ImportSynchronization) KeycloakSession(org.keycloak.models.KeycloakSession) SynchronizationResult(org.keycloak.storage.user.SynchronizationResult)

Example 29 with SynchronizationResult

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

the class LDAPGroupMapperSyncWithGroupsPathTest method test02_syncWithDropNonExistingGroups.

@Test
public void test02_syncWithDropNonExistingGroups() throws Exception {
    testingClient.server().run(session -> {
        LDAPTestContext ctx = LDAPTestContext.init(session);
        RealmModel realm = ctx.getRealm();
        ComponentModel mapperModel = LDAPTestUtils.getSubcomponentByName(realm, ctx.getLdapModel(), "groupsMapper");
        // KEYCLOAK-11415 - This test requires the group mapper to be configured with preserve group inheritance
        // set to 'true' (the default setting). If preservation of group inheritance isn't configured, some of
        // the previous test(s) failed to cleanup properly. Check the requirement as part of running the test
        Assert.assertEquals(mapperModel.getConfig().getFirst("preserve.group.inheritance"), "true");
        // Sync groups with inheritance
        SynchronizationResult syncResult = new GroupLDAPStorageMapperFactory().create(session, mapperModel).syncDataFromFederationProviderToKeycloak(realm);
        LDAPTestAsserts.assertSyncEquals(syncResult, 3, 0, 0, 0);
        // Assert groups are imported to keycloak including their inheritance from LDAP
        GroupModel kcGroup1 = KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1");
        Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1/group11"));
        Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1/group12"));
        Assert.assertEquals(2, kcGroup1.getSubGroupsStream().count());
        // Create some new groups in keycloak
        GroupModel groupsPathGroup = KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH);
        realm.createGroup("model1", groupsPathGroup);
        realm.createGroup("model2", kcGroup1);
        realm.createGroup("outside");
        // Sync groups again from LDAP. Nothing deleted
        syncResult = new GroupLDAPStorageMapperFactory().create(session, mapperModel).syncDataFromFederationProviderToKeycloak(realm);
        LDAPTestAsserts.assertSyncEquals(syncResult, 0, 3, 0, 0);
        Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1/group11"));
        Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1/group12"));
        Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/model1"));
        Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1/model2"));
        Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, "/outside"));
        // Update group mapper to drop non-existing groups during sync
        LDAPTestUtils.updateGroupMapperConfigOptions(mapperModel, GroupMapperConfig.DROP_NON_EXISTING_GROUPS_DURING_SYNC, "true");
        realm.updateComponent(mapperModel);
        // Sync groups again from LDAP. Assert LDAP non-existing groups deleted
        syncResult = new GroupLDAPStorageMapperFactory().create(session, mapperModel).syncDataFromFederationProviderToKeycloak(realm);
        Assert.assertEquals(3, syncResult.getUpdated());
        Assert.assertTrue(syncResult.getRemoved() == 2);
        // Sync and assert groups updated
        Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1/group11"));
        Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1/group12"));
        Assert.assertNull(KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/model1"));
        Assert.assertNull(KeycloakModelUtils.findGroupByPath(realm, LDAP_GROUPS_PATH + "/group1/model2"));
        Assert.assertNotNull(KeycloakModelUtils.findGroupByPath(realm, "/outside"));
    });
}
Also used : RealmModel(org.keycloak.models.RealmModel) ComponentModel(org.keycloak.component.ComponentModel) GroupModel(org.keycloak.models.GroupModel) GroupLDAPStorageMapperFactory(org.keycloak.storage.ldap.mappers.membership.group.GroupLDAPStorageMapperFactory) SynchronizationResult(org.keycloak.storage.user.SynchronizationResult) Test(org.junit.Test)

Example 30 with SynchronizationResult

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

the class UserStorageProviderResource method syncUsers.

/**
 * Trigger sync of users
 *
 * Action can be "triggerFullSync" or "triggerChangedUsersSync"
 *
 * @param id
 * @param action
 * @return
 */
@POST
@Path("{id}/sync")
@NoCache
@Produces(MediaType.APPLICATION_JSON)
public SynchronizationResult syncUsers(@PathParam("id") String id, @QueryParam("action") String action) {
    auth.users().requireManage();
    ComponentModel model = realm.getComponent(id);
    if (model == null) {
        throw new NotFoundException("Could not find component");
    }
    if (!model.getProviderType().equals(UserStorageProvider.class.getName())) {
        throw new NotFoundException("found, but not a UserStorageProvider");
    }
    UserStorageProviderModel providerModel = new UserStorageProviderModel(model);
    logger.debug("Syncing users");
    UserStorageSyncManager syncManager = new UserStorageSyncManager();
    SynchronizationResult syncResult;
    if ("triggerFullSync".equals(action)) {
        syncResult = syncManager.syncAllUsers(session.getKeycloakSessionFactory(), realm.getId(), providerModel);
    } else if ("triggerChangedUsersSync".equals(action)) {
        syncResult = syncManager.syncChangedUsers(session.getKeycloakSessionFactory(), realm.getId(), providerModel);
    } else if (action == null || action == "") {
        logger.debug("Missing action");
        throw new BadRequestException("Missing action");
    } else {
        logger.debug("Unknown action: " + action);
        throw new BadRequestException("Unknown action: " + action);
    }
    Map<String, Object> eventRep = new HashMap<>();
    eventRep.put("action", action);
    eventRep.put("result", syncResult);
    adminEvent.operation(OperationType.ACTION).resourcePath(session.getContext().getUri()).representation(eventRep).success();
    return syncResult;
}
Also used : UserStorageSyncManager(org.keycloak.services.managers.UserStorageSyncManager) HashMap(java.util.HashMap) ComponentModel(org.keycloak.component.ComponentModel) NotFoundException(javax.ws.rs.NotFoundException) BadRequestException(javax.ws.rs.BadRequestException) UserStorageProviderModel(org.keycloak.storage.UserStorageProviderModel) SynchronizationResult(org.keycloak.storage.user.SynchronizationResult) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Produces(javax.ws.rs.Produces) NoCache(org.jboss.resteasy.annotations.cache.NoCache)

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