diff --git a/bundle/src/main/java/io/wcm/caconfig/editor/impl/ConfigDataResponseGenerator.java b/bundle/src/main/java/io/wcm/caconfig/editor/impl/ConfigDataResponseGenerator.java index 03a168e3..698fd409 100644 --- a/bundle/src/main/java/io/wcm/caconfig/editor/impl/ConfigDataResponseGenerator.java +++ b/bundle/src/main/java/io/wcm/caconfig/editor/impl/ConfigDataResponseGenerator.java @@ -40,8 +40,14 @@ import java.util.TreeMap; import java.util.regex.Pattern; +import javax.jcr.RepositoryException; +import javax.jcr.Session; +import javax.jcr.security.AccessControlManager; +import javax.jcr.security.Privilege; + import org.apache.commons.lang3.ClassUtils; import org.apache.commons.lang3.StringUtils; +import org.apache.sling.api.SlingHttpServletRequest; import org.apache.sling.api.resource.Resource; import org.apache.sling.caconfig.management.ConfigurationCollectionData; import org.apache.sling.caconfig.management.ConfigurationData; @@ -74,16 +80,33 @@ class ConfigDataResponseGenerator { private final PathBrowserRootPathProviderService pathBrowserRootPathProviderService; private final TagBrowserRootPathProviderService tagBrowserRootPathProviderService; + private AccessControlManager accessControlManager; + private Privilege jcrWritePrivilege; + private static Logger log = LoggerFactory.getLogger(ConfigDataResponseGenerator.class); - ConfigDataResponseGenerator(ConfigurationManager configManager, ConfigurationPersistenceStrategyMultiplexer configurationPersistenceStrategy, - DropdownOptionProviderService dropdownOptionProviderService, PathBrowserRootPathProviderService pathBrowserRootPathProviderService, - TagBrowserRootPathProviderService tagBrowserRootPathProviderService) { + ConfigDataResponseGenerator(@NotNull SlingHttpServletRequest request, + @NotNull ConfigurationManager configManager, + @NotNull ConfigurationPersistenceStrategyMultiplexer configurationPersistenceStrategy, + @NotNull DropdownOptionProviderService dropdownOptionProviderService, + @NotNull PathBrowserRootPathProviderService pathBrowserRootPathProviderService, + @NotNull TagBrowserRootPathProviderService tagBrowserRootPathProviderService) { this.configManager = configManager; this.configurationPersistenceStrategy = configurationPersistenceStrategy; this.dropdownOptionProviderService = dropdownOptionProviderService; this.pathBrowserRootPathProviderService = pathBrowserRootPathProviderService; this.tagBrowserRootPathProviderService = tagBrowserRootPathProviderService; + + Session session = request.getResourceResolver().adaptTo(Session.class); + if (session != null) { + try { + this.accessControlManager = session.getAccessControlManager(); + this.jcrWritePrivilege = accessControlManager.privilegeFromName(Privilege.JCR_WRITE); + } + catch (RepositoryException ex) { + log.warn("Unable to prepare JCR AccessControlManager.", ex); + } + } } Object getConfiguration(@NotNull Resource contextResource, String configName, boolean collection) { @@ -113,6 +136,7 @@ private ConfigCollectionItem fromConfigCollection(@NotNull Resource contextResou ConfigCollectionItem result = new ConfigCollectionItem(); result.setConfigName(configCollection.getConfigName()); result.setConfigSourcePath(configCollection.getResourcePath()); + result.setReadOnly(isReadOnly(configCollection.getResourcePath())); if (!configCollection.getProperties().isEmpty()) { Map properties = new TreeMap<>(); @@ -133,6 +157,7 @@ private ConfigCollectionItem fromConfigCollection(@NotNull Resource contextResou return result; } + @SuppressWarnings("java:S3776") private ConfigItem fromConfig(@NotNull Resource contextResource, ConfigurationData config, Boolean inherited, String fullConfigName) { ConfigItem result = new ConfigItem(); @@ -141,6 +166,7 @@ private ConfigItem fromConfig(@NotNull Resource contextResource, ConfigurationDa result.setOverridden(config.isOverridden()); result.setInherited(inherited); result.setConfigSourcePath(config.getResourcePath()); + result.setReadOnly(isReadOnly(config.getResourcePath())); List props = new ArrayList<>(); for (String propertyName : config.getPropertyNames()) { @@ -231,7 +257,7 @@ private ConfigItem fromConfig(@NotNull Resource contextResource, ConfigurationDa * @param contextResource Context resource * @return JSON object or null */ - @SuppressWarnings("PMD.ReturnEmptyCollectionRatherThanNull") + @SuppressWarnings({ "PMD.ReturnEmptyCollectionRatherThanNull", "java:S3776" }) private @Nullable Map toJsonWithValueConversion(@Nullable Map properties, @NotNull Resource contextResource) { if (properties == null || properties.isEmpty()) { @@ -318,5 +344,18 @@ private ConfigItem fromConfig(@NotNull Resource contextResource, ConfigurationDa return value; } + private @Nullable Boolean isReadOnly(String resourcePath) { + if (accessControlManager != null && jcrWritePrivilege != null) { + try { + if (!accessControlManager.hasPrivileges(resourcePath, new Privilege[] { jcrWritePrivilege })) { + return true; + } + } + catch (RepositoryException ex) { + log.warn("Unable to check JCR write privilege for resource: {}", resourcePath, ex); + } + } + return null; + } } diff --git a/bundle/src/main/java/io/wcm/caconfig/editor/impl/ConfigDataServlet.java b/bundle/src/main/java/io/wcm/caconfig/editor/impl/ConfigDataServlet.java index 00d5a0d9..fc43ef49 100644 --- a/bundle/src/main/java/io/wcm/caconfig/editor/impl/ConfigDataServlet.java +++ b/bundle/src/main/java/io/wcm/caconfig/editor/impl/ConfigDataServlet.java @@ -95,7 +95,7 @@ protected void doGet(@NotNull SlingHttpServletRequest request, @NotNull SlingHtt // output configuration try { ConfigDataResponseGenerator generator = new ConfigDataResponseGenerator( - configManager, configurationPersistenceStrategy, + request, configManager, configurationPersistenceStrategy, dropdownOptionProviderService, pathBrowserRootPathProviderService, tagBrowserRootPathProviderService); Object result = generator.getConfiguration(request.getResource(), configName, collection); if (result == null) { diff --git a/bundle/src/main/java/io/wcm/caconfig/editor/impl/data/configdata/ConfigCollectionItem.java b/bundle/src/main/java/io/wcm/caconfig/editor/impl/data/configdata/ConfigCollectionItem.java index 930f3e90..7568a086 100644 --- a/bundle/src/main/java/io/wcm/caconfig/editor/impl/data/configdata/ConfigCollectionItem.java +++ b/bundle/src/main/java/io/wcm/caconfig/editor/impl/data/configdata/ConfigCollectionItem.java @@ -34,6 +34,7 @@ public class ConfigCollectionItem { private String configName; private String configSourcePath; + private Boolean readOnly; private Map properties; private Collection items; private ConfigItem newItem; @@ -54,6 +55,14 @@ public void setConfigSourcePath(String configSourcePath) { this.configSourcePath = configSourcePath; } + public Boolean getReadOnly() { + return this.readOnly; + } + + public void setReadOnly(Boolean readOnly) { + this.readOnly = readOnly; + } + public Map getProperties() { return this.properties; } diff --git a/bundle/src/main/java/io/wcm/caconfig/editor/impl/data/configdata/ConfigItem.java b/bundle/src/main/java/io/wcm/caconfig/editor/impl/data/configdata/ConfigItem.java index 3fd97ee3..9e1b4a99 100644 --- a/bundle/src/main/java/io/wcm/caconfig/editor/impl/data/configdata/ConfigItem.java +++ b/bundle/src/main/java/io/wcm/caconfig/editor/impl/data/configdata/ConfigItem.java @@ -36,6 +36,7 @@ public class ConfigItem { private Boolean overridden; private Boolean inherited; private String configSourcePath; + private Boolean readOnly; private Collection properties; public String getConfigName() { @@ -78,6 +79,14 @@ public void setConfigSourcePath(String configSourcePath) { this.configSourcePath = configSourcePath; } + public Boolean getReadOnly() { + return this.readOnly; + } + + public void setReadOnly(Boolean readOnly) { + this.readOnly = readOnly; + } + public Collection getProperties() { return this.properties; }