Acosix / alfresco-keycloak

Alfresco addon to provide Keycloak-related extensions / customisations for Repository and Share
Apache License 2.0
36 stars 20 forks source link

Alfresco - Keycloak ..later Sync #21

Open MarkoArsic opened 3 years ago

MarkoArsic commented 3 years ago

Hi Alex, after few weeks i finally succeeded in configure all with Alfresco 7 in Docker environment. We built a custom Repository and Share images from your latest Utility and This .acs files. You did a great job!!!

A question: Is it possible to add some synchronizations later, beside initial, like a Cron job in the LDAP manner, i don't see any of keycloak.synchronization.import.cron... property existence in your docs?

A use case: In initial sync we have a user in a particular group that has some role. When user changes a group with some other role that change does not reflects in Alfresco, it is not synchronized even with new login if that user.

Do you have any suggestion of how we can accomplish this kind of synchronization? THANK YOU!

AFaust commented 3 years ago

The module already supports and hooks into the default Alfresco synchronization subsystem. There is no need for a separate cron config property because that is what synchronization.import.cron does. Provided you have not disabled the Keycloak synch enablement flag and have configured the correct level of API access for Alfresco to be allowed to query users / groups, it should work out-of-the-box.

MarkoArsic commented 3 years ago

Thank you for quick answer!! keycloak.synchronisation.enabled is TRUE by default. I didn't change it. Repository and Share clients are properly configured according to some of your examples, otherwise the initial synchronization wouldn't work... i guess :-).

After successful docker compose up command every role/group is synced properly , but afterwards i don't see any user-group updates on Alfresco.

EXAMPLE: Initial sync happened, and all users/groups/roles are visible in Alfresco. Later i moved a user from one group to another and that change is not visible on Alfresco Share > Admin tool > Groups. I check that few moments after change, does it take some time for sync, like 24 hours? Also, after i log in with some new user, that does not exists in Alfresco, the full synchronization happens and all previous changes from Keycloak are visible in Alfresco.

Props that are changed for custom Alfresco repository image: /shared/classes/alfresco-global.properties

authentication.chain=keycloak1:keycloak,alfrescoNtlm1:alfrescoNtlm
keycloak.adapter.auth-server-url=http://our_domain.com:port/auth/
keycloak.adapter.realm=OUR_REALM
keycloak.adapter.resource=alfresco
keycloak.adapter.credentials.provider=secret
keycloak.adapter.credentials.secret=REPOSITORY_CLIENT_SECRET
keycloak.adapter.verify-token-audience=false
keycloak.authentication.directAuthHost=http://our_domain.com

Props that are changed for custom Alfresco Share image: /shared/classes/alfresco/web-extension/share-config-custom.xml

  <config evaluator="string-compare" condition="Keycloak">
        <keycloak-auth-config>
            <enhance-login-form>true</enhance-login-form>
            <enable-sso-filter>true</enable-sso-filter>
            <force-keycloak-sso>false</force-keycloak-sso>
            <session-mapper-limit>2000</session-mapper-limit>
            <perform-token-exchange>false</perform-token-exchange>
        </keycloak-auth-config>
        <keycloak-adapter-config>
        <directAuthHost></directAuthHost>
            <auth-server-url>http://OUR_DOMAIN:PORT/auth/</auth-server-url>
            <always-refresh-token>true</always-refresh-token>
            <connection-pool-size>123</connection-pool-size>
            <realm>REALM_NAME</realm>
            <resource>alfresco-share</resource>
            <credentials>
                <provider>secret</provider>
                <secret>SHARE_CLIENT_SECRET</secret>
            </credentials>
        </keycloak-adapter-config>
    </config>
</alfresco-config>
AFaust commented 3 years ago

The default regular Alfresco synchronization happens once per day (at midnight), unless a new / unknown user logs in. So the behaviour as you report it would be "expected".

MarkoArsic commented 3 years ago

Thank you very much! Just one last question, can i make keycloak.synchronization.import.cron if i need multiple synchronizations per day?

AFaust commented 3 years ago

You should adapt the Alfresco property synchronization.import.cron in this case. Simply set a cron that i.e. executes a synchronization every few hours (I have a customer who has it set to every 2 hours). There is absolutely no need for a separate keycloak.synchronization.import.cron.

MarkoArsic commented 3 years ago

Thanks a lot that works, everything got synced as i specified! Just a small note, It is working fine but occasionally Alfresco throw some error in console , usually when there is nothing to sync, do not know why and is it related to Your adapter or Alfresco, check the log if you have time.

custom-alfresco-content-repository | 2021-08-30 13:50:01,436  INFO  [security.sync.ChainingUserRegistrySynchronizer] [DefaultScheduler_Worker-8] Retrieving all users from user registry 'keycloak1'
custom-alfresco-content-repository | 2021-08-30 13:50:01,439  INFO  [security.sync.ChainingUserRegistrySynchronizer] [DefaultScheduler_Worker-8] Synchronization,Category=directory,id1=keycloak1,id2=6 User Creation and Association: Commencing batch of 22 entries
custom-alfresco-content-repository | 2021-08-30 13:50:01,452  INFO  [security.sync.ChainingUserRegistrySynchronizer] [DefaultScheduler_Worker-8] Synchronization,Category=directory,id1=keycloak1,id2=6 User Creation and Association: Processed 22 entries out of 22. 100% complete. Rate: 1692 per second. 0 failures detected.
custom-alfresco-content-repository | 2021-08-30 13:50:01,452  INFO  [security.sync.ChainingUserRegistrySynchronizer] [DefaultScheduler_Worker-8] Synchronization,Category=directory,id1=keycloak1,id2=6 User Creation and Association: Completed batch of 22 entries
custom-alfresco-content-repository | 2021-08-30 13:50:01,452  INFO  [security.sync.ChainingUserRegistrySynchronizer] [DefaultScheduler_Worker-8] Finished synchronizing users and groups with user registry 'keycloak1'
custom-alfresco-content-repository | 2021-08-30 13:50:01,452  INFO  [security.sync.ChainingUserRegistrySynchronizer] [DefaultScheduler_Worker-8] 22 user(s) and 216 group(s) processed
custom-alfresco-content-repository | 2021-08-30 13:55:00,046  INFO  [security.sync.ChainingUserRegistrySynchronizer] [DefaultScheduler_Worker-4] Synchronizing users and groups with user registry 'keycloak1'
custom-alfresco-content-repository | 2021-08-30 13:55:00,046  WARN  [security.sync.ChainingUserRegistrySynchronizer] [DefaultScheduler_Worker-4] Some users and groups previously created by synchronization with this user registry may be removed.
custom-alfresco-content-repository | 2021-08-30 13:55:00,054  INFO  [security.sync.ChainingUserRegistrySynchronizer] [DefaultScheduler_Worker-4] Retrieving all groups from user registry 'keycloak1'
custom-alfresco-content-repository | 2021-08-30 13:55:00,058  INFO  [security.sync.ChainingUserRegistrySynchronizer] [DefaultScheduler_Worker-4] Synchronization,Category=directory,id1=keycloak1,id2=1 Group Analysis: Commencing batch of 216 entries
custom-alfresco-content-repository | 2021-08-30 13:55:01,001  ERROR [repo.client.IDMClientImpl] [DefaultScheduler_Worker-4] Failed to retrieve entities
custom-alfresco-content-repository | java.io.IOException: Bad status: 401
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.client.IDMClientImpl.processEntityBatch(IDMClientImpl.java:442)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.client.IDMClientImpl.processMembers(IDMClientImpl.java:299)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry.mapGroup(KeycloakUserRegistry.java:286)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$KeycloakAuthorityCollection.convert(KeycloakUserRegistry.java:376)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$KeycloakAuthorityCollection$KeycloakAuthorityIterator.lambda$checkAndFillBuffer$0(KeycloakUserRegistry.java:430)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:523)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$processGroupsRecursively$2(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$processGroupsRecursively$2(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$processGroupsRecursively$2(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$processGroupsRecursively$2(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$processGroupsRecursively$2(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$loadNext$0(KeycloakUserRegistry.java:514)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.client.IDMClientImpl.processEntityBatch(IDMClientImpl.java:458)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.client.IDMClientImpl.processGroups(IDMClientImpl.java:271)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.loadNext(KeycloakUserRegistry.java:513)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$KeycloakAuthorityCollection$KeycloakAuthorityIterator.checkAndFillBuffer(KeycloakUserRegistry.java:429)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$KeycloakAuthorityCollection$KeycloakAuthorityIterator.hasNext(KeycloakUserRegistry.java:396)
custom-alfresco-content-repository |    at org.alfresco.repo.batch.BatchProcessor$WorkProviderIterator.hasNext(BatchProcessor.java:607)
custom-alfresco-content-repository |    at org.alfresco.repo.batch.BatchProcessor.process(BatchProcessor.java:394)
custom-alfresco-content-repository |    at org.alfresco.repo.security.sync.ChainingUserRegistrySynchronizer.syncWithPlugin(ChainingUserRegistrySynchronizer.java:1749)
custom-alfresco-content-repository |    at org.alfresco.repo.security.sync.ChainingUserRegistrySynchronizer.synchronizeInternal(ChainingUserRegistrySynchronizer.java:739)
custom-alfresco-content-repository |    at org.alfresco.repo.security.sync.ChainingUserRegistrySynchronizer.synchronize(ChainingUserRegistrySynchronizer.java:471)
custom-alfresco-content-repository |    at org.alfresco.repo.security.sync.UserRegistrySynchronizerJob$1.doWork(UserRegistrySynchronizerJob.java:53)
custom-alfresco-content-repository |    at org.alfresco.repo.security.authentication.AuthenticationUtil.runAs(AuthenticationUtil.java:602)
custom-alfresco-content-repository |    at org.alfresco.repo.security.sync.UserRegistrySynchronizerJob.execute(UserRegistrySynchronizerJob.java:49)
custom-alfresco-content-repository |    at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
custom-alfresco-content-repository |    at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
custom-alfresco-content-repository | 2021-08-30 13:55:01,002  INFO  [security.sync.ChainingUserRegistrySynchronizer] [DefaultScheduler_Worker-4] Synchronization,Category=directory,id1=keycloak1,id2=1 Group Analysis: Completed batch of 216 entries
custom-alfresco-content-repository | 2021-08-30 13:55:01,005  ERROR [security.sync.ChainingUserRegistrySynchronizer] [DefaultScheduler_Worker-4] Synchronization aborted due to error
custom-alfresco-content-repository | org.alfresco.error.AlfrescoRuntimeException: 07300026 Failed to retrieve entities
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.client.IDMClientImpl.processEntityBatch(IDMClientImpl.java:478)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.client.IDMClientImpl.processMembers(IDMClientImpl.java:299)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry.mapGroup(KeycloakUserRegistry.java:286)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$KeycloakAuthorityCollection.convert(KeycloakUserRegistry.java:376)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$KeycloakAuthorityCollection$KeycloakAuthorityIterator.lambda$checkAndFillBuffer$0(KeycloakUserRegistry.java:430)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:523)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$processGroupsRecursively$2(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$processGroupsRecursively$2(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$processGroupsRecursively$2(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$processGroupsRecursively$2(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$processGroupsRecursively$2(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$loadNext$0(KeycloakUserRegistry.java:514)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.client.IDMClientImpl.processEntityBatch(IDMClientImpl.java:458)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.client.IDMClientImpl.processGroups(IDMClientImpl.java:271)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.loadNext(KeycloakUserRegistry.java:513)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$KeycloakAuthorityCollection$KeycloakAuthorityIterator.checkAndFillBuffer(KeycloakUserRegistry.java:429)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$KeycloakAuthorityCollection$KeycloakAuthorityIterator.hasNext(KeycloakUserRegistry.java:396)
custom-alfresco-content-repository |    at org.alfresco.repo.batch.BatchProcessor$WorkProviderIterator.hasNext(BatchProcessor.java:607)
custom-alfresco-content-repository |    at org.alfresco.repo.batch.BatchProcessor.process(BatchProcessor.java:394)
custom-alfresco-content-repository |    at org.alfresco.repo.security.sync.ChainingUserRegistrySynchronizer.syncWithPlugin(ChainingUserRegistrySynchronizer.java:1749)
custom-alfresco-content-repository |    at org.alfresco.repo.security.sync.ChainingUserRegistrySynchronizer.synchronizeInternal(ChainingUserRegistrySynchronizer.java:739)
custom-alfresco-content-repository |    at org.alfresco.repo.security.sync.ChainingUserRegistrySynchronizer.synchronize(ChainingUserRegistrySynchronizer.java:471)
custom-alfresco-content-repository |    at org.alfresco.repo.security.sync.UserRegistrySynchronizerJob$1.doWork(UserRegistrySynchronizerJob.java:53)
custom-alfresco-content-repository |    at org.alfresco.repo.security.authentication.AuthenticationUtil.runAs(AuthenticationUtil.java:602)
custom-alfresco-content-repository |    at org.alfresco.repo.security.sync.UserRegistrySynchronizerJob.execute(UserRegistrySynchronizerJob.java:49)
custom-alfresco-content-repository |    at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
custom-alfresco-content-repository |    at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
custom-alfresco-content-repository | Caused by: java.io.IOException: Bad status: 401
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.client.IDMClientImpl.processEntityBatch(IDMClientImpl.java:442)
custom-alfresco-content-repository |    ... 36 more
custom-alfresco-content-repository | 2021-08-30 13:55:01,045  ERROR [security.sync.ChainingUserRegistrySynchronizer] [DefaultScheduler_Worker-4] Synchronization aborted due to error
custom-alfresco-content-repository | org.alfresco.error.AlfrescoRuntimeException: 07300026 Failed to retrieve entities
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.client.IDMClientImpl.processEntityBatch(IDMClientImpl.java:478)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.client.IDMClientImpl.processMembers(IDMClientImpl.java:299)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry.mapGroup(KeycloakUserRegistry.java:286)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$KeycloakAuthorityCollection.convert(KeycloakUserRegistry.java:376)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$KeycloakAuthorityCollection$KeycloakAuthorityIterator.lambda$checkAndFillBuffer$0(KeycloakUserRegistry.java:430)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:523)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$processGroupsRecursively$2(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$processGroupsRecursively$2(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$processGroupsRecursively$2(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$processGroupsRecursively$2(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$processGroupsRecursively$2(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at java.base/java.util.ArrayList.forEach(ArrayList.java:1541)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.processGroupsRecursively(KeycloakUserRegistry.java:528)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.lambda$loadNext$0(KeycloakUserRegistry.java:514)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.client.IDMClientImpl.processEntityBatch(IDMClientImpl.java:458)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.client.IDMClientImpl.processGroups(IDMClientImpl.java:271)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$GroupCollection.loadNext(KeycloakUserRegistry.java:513)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$KeycloakAuthorityCollection$KeycloakAuthorityIterator.checkAndFillBuffer(KeycloakUserRegistry.java:429)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$KeycloakAuthorityCollection$KeycloakAuthorityIterator.hasNext(KeycloakUserRegistry.java:396)
custom-alfresco-content-repository |    at org.alfresco.repo.batch.BatchProcessor$WorkProviderIterator.hasNext(BatchProcessor.java:607)
custom-alfresco-content-repository |    at org.alfresco.repo.batch.BatchProcessor.process(BatchProcessor.java:394)
custom-alfresco-content-repository |    at org.alfresco.repo.security.sync.ChainingUserRegistrySynchronizer.syncWithPlugin(ChainingUserRegistrySynchronizer.java:1749)
custom-alfresco-content-repository |    at org.alfresco.repo.security.sync.ChainingUserRegistrySynchronizer.synchronizeInternal(ChainingUserRegistrySynchronizer.java:739)
custom-alfresco-content-repository |    at org.alfresco.repo.security.sync.ChainingUserRegistrySynchronizer.synchronize(ChainingUserRegistrySynchronizer.java:471)
custom-alfresco-content-repository |    at org.alfresco.repo.security.sync.UserRegistrySynchronizerJob$1.doWork(UserRegistrySynchronizerJob.java:53)
custom-alfresco-content-repository |    at org.alfresco.repo.security.authentication.AuthenticationUtil.runAs(AuthenticationUtil.java:602)
custom-alfresco-content-repository |    at org.alfresco.repo.security.sync.UserRegistrySynchronizerJob.execute(UserRegistrySynchronizerJob.java:49)
custom-alfresco-content-repository |    at org.quartz.core.JobRunShell.run(JobRunShell.java:202)
custom-alfresco-content-repository |    at org.quartz.simpl.SimpleThreadPool$WorkerThread.run(SimpleThreadPool.java:573)
custom-alfresco-content-repository | Caused by: java.io.IOException: Bad status: 401
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.client.IDMClientImpl.processEntityBatch(IDMClientImpl.java:442)
custom-alfresco-content-repository |    ... 36 more
custom-alfresco-content-repository | 2021-08-30 13:55:01,050  ERROR [quartz.core.JobRunShell] [DefaultScheduler_Worker-4] Job DEFAULT.ldapPeopleJobDetail threw an unhandled Exception: 
custom-alfresco-content-repository | org.alfresco.error.AlfrescoRuntimeException: 07300026 Failed to retrieve entities
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.client.IDMClientImpl.processEntityBatch(IDMClientImpl.java:478)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.client.IDMClientImpl.processMembers(IDMClientImpl.java:299)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry.mapGroup(KeycloakUserRegistry.java:286)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$KeycloakAuthorityCollection.convert(KeycloakUserRegistry.java:376)
custom-alfresco-content-repository |    at de.acosix.alfresco.keycloak.repo.sync.KeycloakUserRegistry$KeycloakAuthorityCollection$KeycloakAuthorityIterator.lambda$checkAndFillBuffer$0(KeycloakUserRegistry.java:430)