From b60fd036ae71cee44cfb83916a9e388d18e6cccb Mon Sep 17 00:00:00 2001 From: Georg Henzler Date: Fri, 21 Jun 2024 16:43:13 +0200 Subject: [PATCH 1/3] Validation to ensure groups with externalId set are not used in isMemberOf Closes #732 --- .../configmodel/GlobalConfiguration.java | 26 ++++++- .../configreader/YamlConfigurationMerger.java | 9 ++- .../ExternalGroupsInIsMemberOfValidator.java | 77 +++++++++++++++++++ ...ExternalGroupUsageValidationException.java | 19 +++++ .../YamlConfigurationMergerTest.java | 4 +- ...ternalGroupsInIsMemberOfValidatorTest.java | 44 +++++++++++ ...externalId-set-correctly-on-role-only.yaml | 27 +++++++ ...st-externalId-set-on-fragment-invalid.yaml | 28 +++++++ ...ent-overruled-by-config-to-be-allowed.yaml | 27 +++++++ docs/Configuration.md | 2 +- 10 files changed, 258 insertions(+), 5 deletions(-) create mode 100644 accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/ExternalGroupsInIsMemberOfValidator.java create mode 100644 accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/exceptions/InvalidExternalGroupUsageValidationException.java create mode 100644 accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/validators/ExternalGroupsInIsMemberOfValidatorTest.java create mode 100644 accesscontroltool-bundle/src/test/resources/externalIds/test-externalId-set-correctly-on-role-only.yaml create mode 100644 accesscontroltool-bundle/src/test/resources/externalIds/test-externalId-set-on-fragment-invalid.yaml create mode 100644 accesscontroltool-bundle/src/test/resources/externalIds/test-externalId-set-on-fragment-overruled-by-config-to-be-allowed.yaml diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configmodel/GlobalConfiguration.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configmodel/GlobalConfiguration.java index a0c4a9d53..555c8ee1f 100644 --- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configmodel/GlobalConfiguration.java +++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configmodel/GlobalConfiguration.java @@ -29,6 +29,7 @@ public class GlobalConfiguration { public static final String KEY_ALLOW_CREATE_OF_UNMANAGED_RELATIONSHIPS = "allowCreateOfUnmanagedRelationships"; + public static final String KEY_ALLOW_EXTERNAL_GROUPS_IN_IS_MEMBER_OF = "allowExternalGroupsInIsMemberOf"; public static final String KEY_AUTOCREATE_TEST_USERS = "autoCreateTestUsers"; @@ -42,6 +43,8 @@ public class GlobalConfiguration { private Pattern defaultUnmanagedExternalMembersRegex; private String defaultUnmanagedAcePathsRegex; private Boolean allowCreateOfUnmanagedRelationships = null; + + private Boolean allowExternalGroupsInIsMemberOf = null; private AutoCreateTestUsersConfig autoCreateTestUsersConfig; @@ -88,6 +91,11 @@ public GlobalConfiguration(Map globalConfigMap) { if (globalConfigMap.containsKey(KEY_AUTOCREATE_TEST_USERS)) { autoCreateTestUsersConfig = new AutoCreateTestUsersConfig((Map) globalConfigMap.get(KEY_AUTOCREATE_TEST_USERS)); } + + if (globalConfigMap.containsKey(KEY_ALLOW_EXTERNAL_GROUPS_IN_IS_MEMBER_OF)) { + setAllowExternalGroupsInIsMemberOf(Boolean.valueOf(globalConfigMap.get(KEY_ALLOW_EXTERNAL_GROUPS_IN_IS_MEMBER_OF).toString())); + } + } } @@ -147,6 +155,14 @@ public void merge(GlobalConfiguration otherGlobalConfig) { } } + if (otherGlobalConfig.getAllowExternalGroupsInIsMemberOf() != null) { + if (allowExternalGroupsInIsMemberOf == null) { + allowExternalGroupsInIsMemberOf = otherGlobalConfig.getAllowExternalGroupsInIsMemberOf(); + } else { + throw new IllegalArgumentException("Duplicate config for " + KEY_ALLOW_EXTERNAL_GROUPS_IN_IS_MEMBER_OF); + } + } + } public String getMinRequiredVersion() { @@ -205,7 +221,13 @@ static Pattern stringToRegex(String regex) { public AutoCreateTestUsersConfig getAutoCreateTestUsersConfig() { return autoCreateTestUsersConfig; } - - + public Boolean getAllowExternalGroupsInIsMemberOf() { + return allowExternalGroupsInIsMemberOf; + } + + public void setAllowExternalGroupsInIsMemberOf(Boolean allowExternalGroupsInIsMemberOf) { + this.allowExternalGroupsInIsMemberOf = allowExternalGroupsInIsMemberOf; + } + } diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configreader/YamlConfigurationMerger.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configreader/YamlConfigurationMerger.java index 5dabb8fbc..8a293fd74 100644 --- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configreader/YamlConfigurationMerger.java +++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/configreader/YamlConfigurationMerger.java @@ -45,6 +45,7 @@ import biz.netcentric.cq.tools.actool.history.impl.PersistableInstallationLogger; import biz.netcentric.cq.tools.actool.slingsettings.ExtendedSlingSettingsService; import biz.netcentric.cq.tools.actool.validators.AuthorizableValidator; +import biz.netcentric.cq.tools.actool.validators.ExternalGroupsInIsMemberOfValidator; import biz.netcentric.cq.tools.actool.validators.ConfigurationsValidator; import biz.netcentric.cq.tools.actool.validators.GlobalConfigurationValidator; import biz.netcentric.cq.tools.actool.validators.ObsoleteAuthorizablesValidator; @@ -68,6 +69,9 @@ public class YamlConfigurationMerger implements ConfigurationMerger { @Reference(policyOption = ReferencePolicyOption.GREEDY) ObsoleteAuthorizablesValidator obsoleteAuthorizablesValidator; + @Reference(policyOption = ReferencePolicyOption.GREEDY) + ExternalGroupsInIsMemberOfValidator externalGroupsInIsMemberOfValidator; + @Reference(policyOption = ReferencePolicyOption.GREEDY) VirtualGroupProcessor virtualGroupProcessor; @@ -222,7 +226,9 @@ public AcConfiguration getMergedConfigurations( if(!Boolean.TRUE.equals(globalConfiguration.getAllowCreateOfUnmanagedRelationships())) { UnmangedExternalMemberRelationshipChecker.validate(acConfiguration); } - + + externalGroupsInIsMemberOfValidator.validateIsMemberOfConfig(acConfiguration, installLog, globalConfiguration); + installLog.setMergedAndProcessedConfig( "# Merged configuration of " + configFileContentByFilename.size() + " files \n" + acConfiguration); @@ -231,6 +237,7 @@ public AcConfiguration getMergedConfigurations( return acConfiguration; } + private Map getGlobalVariablesForYamlMacroProcessing() { Map globalVariables = new HashMap<>(); if(slingSettingsService != null) { diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/ExternalGroupsInIsMemberOfValidator.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/ExternalGroupsInIsMemberOfValidator.java new file mode 100644 index 000000000..9ad768968 --- /dev/null +++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/ExternalGroupsInIsMemberOfValidator.java @@ -0,0 +1,77 @@ +/* + * (C) Copyright 2024 Netcentric AG. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package biz.netcentric.cq.tools.actool.validators; + +import java.util.Arrays; +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.stream.Collectors; + +import org.apache.commons.lang3.StringUtils; +import org.osgi.service.component.annotations.Component; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import biz.netcentric.cq.tools.actool.configmodel.AcConfiguration; +import biz.netcentric.cq.tools.actool.configmodel.AuthorizableConfigBean; +import biz.netcentric.cq.tools.actool.configmodel.AuthorizablesConfig; +import biz.netcentric.cq.tools.actool.configmodel.GlobalConfiguration; +import biz.netcentric.cq.tools.actool.history.impl.PersistableInstallationLogger; +import biz.netcentric.cq.tools.actool.validators.exceptions.InvalidExternalGroupUsageValidationException; + +@Component(service = ExternalGroupsInIsMemberOfValidator.class) +public class ExternalGroupsInIsMemberOfValidator { + private static final Logger LOG = LoggerFactory.getLogger(ExternalGroupsInIsMemberOfValidator.class); + + public void validateIsMemberOfConfig(AcConfiguration acConfiguration, PersistableInstallationLogger installLog, + GlobalConfiguration globalConfiguration) throws InvalidExternalGroupUsageValidationException { + List externalGroupsValidationResults = checkIsMemberOfConfigsOfAllAuthorizables(acConfiguration); + if (!externalGroupsValidationResults.isEmpty()) { + + externalGroupsValidationResults.stream().forEach(m -> installLog.addWarning(LOG, m)); + + String validationMsg = "Found " + externalGroupsValidationResults.size() + " group(s) that use external groups in isMemberOf. "; + + if (Boolean.TRUE.equals(globalConfiguration.getAllowExternalGroupsInIsMemberOf())) { + installLog.addWarning(LOG, validationMsg); + installLog.addWarning(LOG, "Found global config 'allowExternalGroupsInIsMemberOf: true': PLEASE REFACTOR your groups structure to not use external groups in isMemberOf."); + } else { + installLog.addError(LOG, validationMsg + " If absolutely needed, use 'allowExternalGroupsInIsMemberOf: true' in global configuration, but prefer to refactor your groups structure to not use isMemberOf together with external groups.", null); + throw new InvalidExternalGroupUsageValidationException(validationMsg); + } + } + } + + private List checkIsMemberOfConfigsOfAllAuthorizables(AcConfiguration acConfiguration) { + + List validationErrors = new LinkedList<>(); + + AuthorizablesConfig authorizablesConfig = acConfiguration.getAuthorizablesConfig(); + for (AuthorizableConfigBean authorizableConfigBean : authorizablesConfig) { + if(authorizableConfigBean.getIsMemberOf() == null) { + continue; + } + + List groupIdsWithExternalIdSet = Arrays.stream(authorizableConfigBean.getIsMemberOf()) + .map(aId -> acConfiguration.getAuthorizablesConfig().getAuthorizableConfig(aId)) + .filter(Objects::nonNull) + .filter(authBean -> StringUtils.isNotBlank(authBean.getExternalId())) + .map(AuthorizableConfigBean::getAuthorizableId) + .collect(Collectors.toList()); + + if (!groupIdsWithExternalIdSet.isEmpty()) { + validationErrors.add("The authorizable " + authorizableConfigBean.getAuthorizableId() + + " cannot use external group(s) in isMemberOf list: " + StringUtils.join(groupIdsWithExternalIdSet, ",")); + } + } + + return validationErrors; + } +} diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/exceptions/InvalidExternalGroupUsageValidationException.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/exceptions/InvalidExternalGroupUsageValidationException.java new file mode 100644 index 000000000..d1fe982db --- /dev/null +++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/exceptions/InvalidExternalGroupUsageValidationException.java @@ -0,0 +1,19 @@ +/* + * (C) Copyright 2015 Netcentric AG. + * + * All rights reserved. This program and the accompanying materials + * are made available under the terms of the Eclipse Public License v1.0 + * which accompanies this distribution, and is available at + * http://www.eclipse.org/legal/epl-v10.html + */ +package biz.netcentric.cq.tools.actool.validators.exceptions; + +public class InvalidExternalGroupUsageValidationException extends AcConfigBeanValidationException { + public InvalidExternalGroupUsageValidationException(String message) { + super(message); + } + + public InvalidExternalGroupUsageValidationException(String message, Throwable cause) { + super(message, cause); + } +} diff --git a/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/configreader/YamlConfigurationMergerTest.java b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/configreader/YamlConfigurationMergerTest.java index c3214213f..692e1b196 100644 --- a/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/configreader/YamlConfigurationMergerTest.java +++ b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/configreader/YamlConfigurationMergerTest.java @@ -12,8 +12,8 @@ import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertNotNull; -import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.spy; import static org.mockito.MockitoAnnotations.initMocks; @@ -38,6 +38,7 @@ import biz.netcentric.cq.tools.actool.configmodel.AuthorizableConfigBean; import biz.netcentric.cq.tools.actool.configmodel.AuthorizablesConfig; import biz.netcentric.cq.tools.actool.history.impl.PersistableInstallationLogger; +import biz.netcentric.cq.tools.actool.validators.ExternalGroupsInIsMemberOfValidator; import biz.netcentric.cq.tools.actool.validators.exceptions.AcConfigBeanValidationException; import biz.netcentric.cq.tools.actool.validators.impl.ObsoleteAuthorizablesValidatorImpl; @@ -151,6 +152,7 @@ public static YamlConfigurationMerger getConfigurationMerger() { merger.obsoleteAuthorizablesValidator = new ObsoleteAuthorizablesValidatorImpl(); merger.virtualGroupProcessor = new VirtualGroupProcessor(); merger.testUserConfigsCreator = new TestUserConfigsCreator(); + merger.externalGroupsInIsMemberOfValidator = new ExternalGroupsInIsMemberOfValidator(); return merger; } } diff --git a/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/validators/ExternalGroupsInIsMemberOfValidatorTest.java b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/validators/ExternalGroupsInIsMemberOfValidatorTest.java new file mode 100644 index 000000000..fd1c33dd8 --- /dev/null +++ b/accesscontroltool-bundle/src/test/java/biz/netcentric/cq/tools/actool/validators/ExternalGroupsInIsMemberOfValidatorTest.java @@ -0,0 +1,44 @@ +package biz.netcentric.cq.tools.actool.validators; + +import static biz.netcentric.cq.tools.actool.configreader.YamlConfigurationMergerTest.getAcConfigurationForFile; +import static biz.netcentric.cq.tools.actool.configreader.YamlConfigurationMergerTest.getConfigurationMerger; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; + +import javax.jcr.Session; + +import org.junit.jupiter.api.Test; +import org.mockito.Mock; + +import biz.netcentric.cq.tools.actool.configmodel.AcConfiguration; +import biz.netcentric.cq.tools.actool.validators.exceptions.InvalidExternalGroupUsageValidationException; + +class ExternalGroupsInIsMemberOfValidatorTest { + + @Mock + Session session; + + @Test + public void testExternalIdSetCorrectlyOnRoleOnly() throws Exception { + AcConfiguration acConfigurationForFile = getAcConfigurationForFile(getConfigurationMerger(), session, + "externalIds/test-externalId-set-correctly-on-role-only.yaml"); + + assertEquals(3, acConfigurationForFile.getAuthorizablesConfig().size()); + } + + @Test + public void testExternalIdSetOnFragmentOverruledByConfigToBeAlllowed() throws Exception { + AcConfiguration acConfigurationForFile = getAcConfigurationForFile(getConfigurationMerger(), session, + "externalIds/test-externalId-set-on-fragment-overruled-by-config-to-be-allowed.yaml"); + + assertEquals(3, acConfigurationForFile.getAuthorizablesConfig().size()); + } + + @Test + public void testExternalIdSetOnFragmentInvalid() { + assertThrows(InvalidExternalGroupUsageValidationException.class, + () -> getAcConfigurationForFile(getConfigurationMerger(), session, + "externalIds/test-externalId-set-on-fragment-invalid.yaml")); + } + +} diff --git a/accesscontroltool-bundle/src/test/resources/externalIds/test-externalId-set-correctly-on-role-only.yaml b/accesscontroltool-bundle/src/test/resources/externalIds/test-externalId-set-correctly-on-role-only.yaml new file mode 100644 index 000000000..32f77ae2f --- /dev/null +++ b/accesscontroltool-bundle/src/test/resources/externalIds/test-externalId-set-correctly-on-role-only.yaml @@ -0,0 +1,27 @@ +# +# (C) Copyright 2024 Netcentric AG. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# + +- global_config: + + # default - no extra config set + # allowExternalGroupsInIsMemberOf: true + +- group_config: + + - fragment-1: + - name: "Fragment 1" + + - fragment-2: + - name: "Fragment 2" + + - role-1: + - name: "Role 1" + isMemberOf: fragment-1, fragment-2 + externalId: role-1;ims + diff --git a/accesscontroltool-bundle/src/test/resources/externalIds/test-externalId-set-on-fragment-invalid.yaml b/accesscontroltool-bundle/src/test/resources/externalIds/test-externalId-set-on-fragment-invalid.yaml new file mode 100644 index 000000000..d2892ce9d --- /dev/null +++ b/accesscontroltool-bundle/src/test/resources/externalIds/test-externalId-set-on-fragment-invalid.yaml @@ -0,0 +1,28 @@ +# +# (C) Copyright 2024 Netcentric AG. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# + +- global_config: + + # default - no extra config set + # allowExternalGroupsInIsMemberOf: true + +- group_config: + + - fragment-1: + - name: "Fragment 1" + + - fragment-2: + - name: "Fragment 2" + externalId: fragment-2;ims + + - role-1: + - name: "Role 1" + isMemberOf: fragment-1, fragment-2 + + diff --git a/accesscontroltool-bundle/src/test/resources/externalIds/test-externalId-set-on-fragment-overruled-by-config-to-be-allowed.yaml b/accesscontroltool-bundle/src/test/resources/externalIds/test-externalId-set-on-fragment-overruled-by-config-to-be-allowed.yaml new file mode 100644 index 000000000..7775cccab --- /dev/null +++ b/accesscontroltool-bundle/src/test/resources/externalIds/test-externalId-set-on-fragment-overruled-by-config-to-be-allowed.yaml @@ -0,0 +1,27 @@ +# +# (C) Copyright 2024 Netcentric AG. +# +# All rights reserved. This program and the accompanying materials +# are made available under the terms of the Eclipse Public License v1.0 +# which accompanies this distribution, and is available at +# http://www.eclipse.org/legal/epl-v10.html +# + +- global_config: + + allowExternalGroupsInIsMemberOf: true + +- group_config: + + - fragment-1: + - name: "Fragment 1" + + - fragment-2: + - name: "Fragment 2" + externalId: fragment-2;ims + + - role-1: + - name: "Role 1" + isMemberOf: fragment-1, fragment-2 + + diff --git a/docs/Configuration.md b/docs/Configuration.md index 5529b700f..0e86090ff 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -52,7 +52,7 @@ property | comment | required --- | --- | --- name | Name of the group as shown in UI. Sets the property `profile/givenName` of that group. | optional description | Description of the group | optional -externalId | Required for groups which are synchronized from [external sources](https://jackrabbit.apache.org/oak/docs/security/authentication/externalloginmodule.html) like [LDAP](https://jackrabbit.apache.org/oak/docs/security/authentication/ldap.html) or [Adobe IMS](https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/security/ims-support#aem-configuration). This establishes a connection between an (internal) JCR group and an externally managed group (and is persisted in the group's node in the property `rep:externalId`). The value has to be in format `;`. How the external ID and provider name look like is *External Identity Provider dependent*: For **Adobe IMS** it usually is `;ims` while for **Oak LDAP** it usually is `;` where LDAP-DN is the full distinguished name and IDP-NAME is configured in OSGI config PID `org.apache.jackrabbit.oak.security.authentication.ldap.impl.LdapIdentityProvider` property `provider-name`. LDAP Example: `externalId: "cn=group-name,ou=mydepart,ou=Groups,dc=comp,dc=com;IDPNAME"`. Make sure to also set the group id according to how it is extracted by the external identify provider (configurable via OSGi configuration of the external identity provider). Since v1.9.3 | optional +externalId | Required for groups which are synchronized from [external sources](https://jackrabbit.apache.org/oak/docs/security/authentication/externalloginmodule.html) like [LDAP](https://jackrabbit.apache.org/oak/docs/security/authentication/ldap.html) or [Adobe IMS](https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/security/ims-support#aem-configuration). This establishes a connection between an (internal) JCR group and an externally managed group (and is persisted in the group's node in the property `rep:externalId`). The value has to be in format `;`. How the external ID and provider name look like is *External Identity Provider dependent*: For **Adobe IMS** it usually is `;ims` while for **Oak LDAP** it usually is `;` where LDAP-DN is the full distinguished name and IDP-NAME is configured in OSGI config PID `org.apache.jackrabbit.oak.security.authentication.ldap.impl.LdapIdentityProvider` property `provider-name`. LDAP Example: `externalId: "cn=group-name,ou=mydepart,ou=Groups,dc=comp,dc=com;IDPNAME"`. Make sure to also set the group id according to how it is extracted by the external identify provider (configurable via OSGi configuration of the external identity provider). Using groups being synced from external sources in `isMemberOf` will cause an error to avoid problems with dynamic memberships. Use `allowExternalGroupsInIsMemberOf: true` in `global_config` if you need to override this behaviour (should be used rarely). Since v1.9.3 | optional path | Path of the intermediate node either relative or absolute. If relative, `/home/groups` is automatically prefixed. By default some implementation specific path is choosen. Usually the full group path is the (intermediate) path concatenated with a [randomized authorizable id](https://jackrabbit.apache.org/oak/docs/apidocs/org/apache/jackrabbit/oak/security/user/RandomAuthorizableNodeName.html). | optional isMemberOf | List of groups this groups is a member of. May be provided as yaml list or as comma-separated yaml string (*the use of comma-separated yaml strings is deprecated*, available to remain backwards compatible). | optional memberOf | Same meaning as `isMemberOf`. This property is *deprecated*, please use `isMemberOf` instead. | optional From 62182ec91181d217367c9207f1610caa1f3f2c59 Mon Sep 17 00:00:00 2001 From: Georg Henzler Date: Mon, 24 Jun 2024 16:50:29 +0200 Subject: [PATCH 2/3] Add link to dynamic group documentation for #732 --- docs/Configuration.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/Configuration.md b/docs/Configuration.md index 0e86090ff..5c256c335 100644 --- a/docs/Configuration.md +++ b/docs/Configuration.md @@ -52,7 +52,7 @@ property | comment | required --- | --- | --- name | Name of the group as shown in UI. Sets the property `profile/givenName` of that group. | optional description | Description of the group | optional -externalId | Required for groups which are synchronized from [external sources](https://jackrabbit.apache.org/oak/docs/security/authentication/externalloginmodule.html) like [LDAP](https://jackrabbit.apache.org/oak/docs/security/authentication/ldap.html) or [Adobe IMS](https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/security/ims-support#aem-configuration). This establishes a connection between an (internal) JCR group and an externally managed group (and is persisted in the group's node in the property `rep:externalId`). The value has to be in format `;`. How the external ID and provider name look like is *External Identity Provider dependent*: For **Adobe IMS** it usually is `;ims` while for **Oak LDAP** it usually is `;` where LDAP-DN is the full distinguished name and IDP-NAME is configured in OSGI config PID `org.apache.jackrabbit.oak.security.authentication.ldap.impl.LdapIdentityProvider` property `provider-name`. LDAP Example: `externalId: "cn=group-name,ou=mydepart,ou=Groups,dc=comp,dc=com;IDPNAME"`. Make sure to also set the group id according to how it is extracted by the external identify provider (configurable via OSGi configuration of the external identity provider). Using groups being synced from external sources in `isMemberOf` will cause an error to avoid problems with dynamic memberships. Use `allowExternalGroupsInIsMemberOf: true` in `global_config` if you need to override this behaviour (should be used rarely). Since v1.9.3 | optional +externalId | Required for groups which are synchronized from [external sources](https://jackrabbit.apache.org/oak/docs/security/authentication/externalloginmodule.html) like [LDAP](https://jackrabbit.apache.org/oak/docs/security/authentication/ldap.html) or [Adobe IMS](https://experienceleague.adobe.com/en/docs/experience-manager-cloud-service/content/security/ims-support#aem-configuration). This establishes a connection between an (internal) JCR group and an externally managed group (and is persisted in the group's node in the property `rep:externalId`). The value has to be in format `;`. How the external ID and provider name look like is *External Identity Provider dependent*: For **Adobe IMS** it usually is `;ims` while for **Oak LDAP** it usually is `;` where LDAP-DN is the full distinguished name and IDP-NAME is configured in OSGI config PID `org.apache.jackrabbit.oak.security.authentication.ldap.impl.LdapIdentityProvider` property `provider-name`. LDAP Example: `externalId: "cn=group-name,ou=mydepart,ou=Groups,dc=comp,dc=com;IDPNAME"`. Make sure to also set the group id according to how it is extracted by the external identify provider (configurable via OSGi configuration of the external identity provider). Using groups being synced from external sources in `isMemberOf` will cause an error to avoid problems with [dynamic memberships](https://jackrabbit.apache.org/oak/docs/security/authentication/external/dynamic.html). Use `allowExternalGroupsInIsMemberOf: true` in `global_config` if you need to override this behaviour (should be used rarely). Since v1.9.3 | optional path | Path of the intermediate node either relative or absolute. If relative, `/home/groups` is automatically prefixed. By default some implementation specific path is choosen. Usually the full group path is the (intermediate) path concatenated with a [randomized authorizable id](https://jackrabbit.apache.org/oak/docs/apidocs/org/apache/jackrabbit/oak/security/user/RandomAuthorizableNodeName.html). | optional isMemberOf | List of groups this groups is a member of. May be provided as yaml list or as comma-separated yaml string (*the use of comma-separated yaml strings is deprecated*, available to remain backwards compatible). | optional memberOf | Same meaning as `isMemberOf`. This property is *deprecated*, please use `isMemberOf` instead. | optional From 77fed31932f214418029d95975e45b38b0be1138 Mon Sep 17 00:00:00 2001 From: Georg Henzler Date: Mon, 24 Jun 2024 16:58:00 +0200 Subject: [PATCH 3/3] Corrected log #732 --- .../actool/validators/ExternalGroupsInIsMemberOfValidator.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/ExternalGroupsInIsMemberOfValidator.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/ExternalGroupsInIsMemberOfValidator.java index 9ad768968..0797f2fbd 100644 --- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/ExternalGroupsInIsMemberOfValidator.java +++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/validators/ExternalGroupsInIsMemberOfValidator.java @@ -37,7 +37,7 @@ public void validateIsMemberOfConfig(AcConfiguration acConfiguration, Persistabl externalGroupsValidationResults.stream().forEach(m -> installLog.addWarning(LOG, m)); - String validationMsg = "Found " + externalGroupsValidationResults.size() + " group(s) that use external groups in isMemberOf. "; + String validationMsg = "Found " + externalGroupsValidationResults.size() + " authorizable(s) that use external groups in isMemberOf. "; if (Boolean.TRUE.equals(globalConfiguration.getAllowExternalGroupsInIsMemberOf())) { installLog.addWarning(LOG, validationMsg);