Skip to content

Commit

Permalink
Check write permissions for configurations, show storage path (#31)
Browse files Browse the repository at this point in the history
  • Loading branch information
stefanseifert authored Apr 10, 2024
1 parent 643ce3b commit 50ecfcc
Show file tree
Hide file tree
Showing 29 changed files with 407 additions and 74 deletions.
7 changes: 7 additions & 0 deletions bundle/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,13 @@

<dependencies>

<dependency>
<groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.testing.sling-mock-oak</artifactId>
<version>3.1.10-1.44.0</version>
<scope>test</scope>
</dependency>

<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -74,9 +80,13 @@ 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(@NotNull ConfigurationManager configManager,
ConfigDataResponseGenerator(@NotNull SlingHttpServletRequest request,
@NotNull ConfigurationManager configManager,
@NotNull ConfigurationPersistenceStrategyMultiplexer configurationPersistenceStrategy,
@NotNull DropdownOptionProviderService dropdownOptionProviderService,
@NotNull PathBrowserRootPathProviderService pathBrowserRootPathProviderService,
Expand All @@ -86,6 +96,17 @@ class ConfigDataResponseGenerator {
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) {
Expand Down Expand Up @@ -114,6 +135,8 @@ private ConfigCollectionItem fromConfigCollection(@NotNull Resource contextResou
ConfigurationCollectionData configCollection, ConfigurationData newItem, String fullConfigName) {
ConfigCollectionItem result = new ConfigCollectionItem();
result.setConfigName(configCollection.getConfigName());
result.setConfigSourcePath(configCollection.getResourcePath());
result.setReadOnly(isReadOnly(configCollection.getResourcePath(), false));

if (!configCollection.getProperties().isEmpty()) {
Map<String, Object> properties = new TreeMap<>();
Expand Down Expand Up @@ -142,6 +165,8 @@ private ConfigItem fromConfig(@NotNull Resource contextResource, ConfigurationDa
result.setCollectionItemName(config.getCollectionItemName());
result.setOverridden(config.isOverridden());
result.setInherited(inherited);
result.setConfigSourcePath(config.getResourcePath());
result.setReadOnly(isReadOnly(config.getResourcePath(), config.isOverridden()));

List<PropertyItem> props = new ArrayList<>();
for (String propertyName : config.getPropertyNames()) {
Expand Down Expand Up @@ -201,6 +226,7 @@ private ConfigItem fromConfig(@NotNull Resource contextResource, ConfigurationDa
prop.setIsDefault(item.isDefault());
prop.setInherited(item.isInherited());
prop.setOverridden(item.isOverridden());
prop.setReadOnly(result.getReadOnly());

if (itemMetadata != null) {
PropertyItemMetadata metadata = new PropertyItemMetadata();
Expand Down Expand Up @@ -319,4 +345,21 @@ private ConfigItem fromConfig(@NotNull Resource contextResource, ConfigurationDa
return value;
}

private @Nullable Boolean isReadOnly(@Nullable String resourcePath, boolean isOverridden) {
if (accessControlManager != null && jcrWritePrivilege != null) {
try {
if (isOverridden) {
return true;
}
else if (resourcePath != null) {
return !accessControlManager.hasPrivileges(resourcePath, new Privilege[] { jcrWritePrivilege });
}
}
catch (RepositoryException ex) {
log.warn("Unable to check JCR write privilege for resource: {}", resourcePath, ex);
}
}
return null;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
public class ConfigCollectionItem {

private String configName;
private String configSourcePath;
private Boolean readOnly;
private Map<String, Object> properties;
private Collection<ConfigItem> items;
private ConfigItem newItem;
Expand All @@ -45,6 +47,22 @@ public void setConfigName(String configName) {
this.configName = configName;
}

public String getConfigSourcePath() {
return this.configSourcePath;
}

public void setConfigSourcePath(String configSourcePath) {
this.configSourcePath = configSourcePath;
}

public Boolean getReadOnly() {
return this.readOnly;
}

public void setReadOnly(Boolean readOnly) {
this.readOnly = readOnly;
}

public Map<String, Object> getProperties() {
return this.properties;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@ public class ConfigItem {
private String collectionItemName;
private Boolean overridden;
private Boolean inherited;
private String configSourcePath;
private Boolean readOnly;
private Collection<PropertyItem> properties;

public String getConfigName() {
Expand Down Expand Up @@ -69,6 +71,22 @@ public void setInherited(Boolean inherited) {
this.inherited = inherited;
}

public String getConfigSourcePath() {
return this.configSourcePath;
}

public void setConfigSourcePath(String configSourcePath) {
this.configSourcePath = configSourcePath;
}

public Boolean getReadOnly() {
return this.readOnly;
}

public void setReadOnly(Boolean readOnly) {
this.readOnly = readOnly;
}

public Collection<PropertyItem> getProperties() {
return this.properties;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ public class PropertyItem {
private Boolean isDefault;
private Boolean inherited;
private Boolean overridden;
private Boolean readOnly;
private PropertyItemMetadata metadata;
private ConfigItem nestedConfig;
private ConfigCollectionItem nestedConfigCollection;
Expand Down Expand Up @@ -99,6 +100,14 @@ public void setOverridden(Boolean overridden) {
this.overridden = overridden;
}

public Boolean getReadOnly() {
return this.readOnly;
}

public void setReadOnly(Boolean readOnly) {
this.readOnly = readOnly;
}

public PropertyItemMetadata getMetadata() {
return this.metadata;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ <h3 bo-text="config.collectionItemName"></h3>
<p class="caconfig-if-is-preview">
<span class="caconfig-edit-config caconfig-link coral-Link" bo-text="i18n('config.edit')" tabindex="0"></span>
</p>
<div class="caconfig-if-not-preview caconfig-if-config-not-inherited caconfig-if-config-not-overridden">
<div class="caconfig-if-not-preview caconfig-if-config-not-inherited caconfig-if-config-not-overridden-and-not-readonly"">
<label class="coral-Checkbox">
<input class="coral-Checkbox-input" type="checkbox"
ng-model="configPropertyInherit.value"
Expand Down
11 changes: 8 additions & 3 deletions bundle/src/main/resources/angularjs-partials/detailView.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
<button is="coral-button" variant="primary"
class="caconfig-if-form-valid-and-dirty"
ng-click="detail.saveConfig()"
bo-disabled="detail.current.readOnly"
bo-if="i18n('button.save') && !!detail.current.contextPath"
bo-text="i18n('button.save')"
></button>
Expand All @@ -28,12 +29,15 @@
bo-title="detail.current.isCollection ? i18n('button.deleteCollection') : i18n('button.deleteConfig')"
ng-show="detail.current.configs.length"
bo-if="detail.current.contextPath"
bo-disabled="detail.current.readOnly"
ng-click="detail.removeConfig()"
></button>

<p class="caconfig-contextPath"
bo-if="detail.current.contextPath">
<span bo-text="i18n('contextPath')"></span>: <code bo-text="detail.current.contextPath"></code>
<caconfig-help-inline-popup bo-if="detail.current.configSourcePath"
content="i18n('configSourcePath') + ' ' + detail.current.configSourcePath"></caconfig-help-inline-popup>
</p>
<p class="caconfig-contextPath"
bo-if="!detail.current.contextPath" bo-text="i18n('noContextPath')">
Expand All @@ -52,7 +56,7 @@ <h2>
<p bo-text="detail.current.description"></p>

<p class="caconfig-collectionInheritance coral-Well"
bo-if="detail.current.isCollection">
bo-if="detail.current.isCollection && !detail.current.readOnly">
<label class="coral-Checkbox">
<input class="coral-Checkbox-input" type="checkbox"
ng-model="detail.current.collectionProperties['sling:configCollectionInherit']">
Expand All @@ -61,7 +65,7 @@ <h2>
</label>
</p>

<p bo-if="detail.current.isCollection">
<p bo-if="detail.current.isCollection && !detail.current.readOnly">
<button is="coral-button" variant="primary"
ng-click="detail.addCollectionItem()"
bo-if="i18n('button.addItem')"
Expand Down Expand Up @@ -98,6 +102,7 @@ <h2>
bo-class="[
config.inherited ? 'caconfig-config-inherited' : 'caconfig-config-not-inherited',
config.overridden ? 'caconfig-config-overridden' : 'caconfig-config-not-overridden',
config.readOnly ? 'caconfig-config-readonly' : 'caconfig-config-not-readonly',
config.isNewItem ? 'caconfig-is-new-item' : 'caconfig-not-new-item',
detail.current.isLargeCollection ? 'caconfig-is-preview' : 'caconfig-not-preview'
]"
Expand All @@ -108,7 +113,7 @@ <h2>
ng-cloak>
</div>

<p bo-if="detail.current.isCollection"
<p bo-if="detail.current.isCollection && !detail.current.readOnly"
ng-show="detail.current.configs.length && detail.allConfigsVisible">

<button is="coral-button" variant="primary"
Expand Down
12 changes: 6 additions & 6 deletions bundle/src/main/resources/angularjs-partials/multifield.html
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
<div bindonce>
<div class="caconfig-multifield caconfig-multifield--empty caconfig-if-property-not-overridden-and-not-inherited"
<div class="caconfig-multifield caconfig-multifield--empty caconfig-if-property-not-overridden-and-not-inherited-and-not-readonly"
ng-if="!(values.length)">
<label class="coral-Checkbox"
bo-if="type==='checkbox'">
Expand All @@ -24,7 +24,7 @@
</div>
</div>

<div class="caconfig-multifield caconfig-if-property-overridden-or-inherited"
<div class="caconfig-multifield caconfig-if-property-overridden-or-inherited-or-readonly"
ng-repeat="effectiveValue in effectiveValues">
<label class="coral-Checkbox"
bo-if="type==='checkbox'">
Expand All @@ -47,7 +47,7 @@
</div>
</div>

<div class="caconfig-multifield caconfig-if-config-inherited caconfig-if-property-not-overridden-and-not-inherited"
<div class="caconfig-multifield caconfig-if-config-inherited caconfig-if-property-not-overridden-and-not-inherited-and-not-readonly"
ng-repeat="value in values">
<label class="coral-Checkbox"
bo-if="type==='checkbox'">
Expand All @@ -70,13 +70,13 @@
</div>
</div>

<div class="caconfig-multifield caconfig-if-config-not-inherited caconfig-if-property-not-overridden-and-not-inherited"
<div class="caconfig-multifield caconfig-if-config-not-inherited caconfig-if-property-not-overridden-and-not-inherited-and-not-readonly"
ng-repeat="value in values" ng-form="inputMultifieldForm">
<label class="coral-Checkbox" style="margin-right:10px;"
bo-if="type==='checkbox'">
<input class="coral-Checkbox-input" type="checkbox"
ng-model="value.value"
ng-required="{{property.metadata.properties.required && !property.overridden && !property.inherited}}"
ng-required="{{property.metadata.properties.required && !property.overridden && !property.inherited && !property.readOnly}}"
name="inputField"/>
<span class="coral-Checkbox-checkmark"></span>
</label>
Expand All @@ -86,7 +86,7 @@
ng-model="value.value"
ng-trim="false"
ng-pattern="pattern"
ng-required="{{property.metadata.properties.required && !property.overridden && !property.inherited}}"
ng-required="{{property.metadata.properties.required && !property.overridden && !property.inherited && !property.readOnly}}"
caconfig-validation="{{validation}}"
name="inputField"/>
<div class="coral-Form-errorlabel" bindonce="i18n('validation.required')" ng-show="inputMultifieldForm.inputField.$error.required" bo-text="i18n('validation.required')"></div>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -60,12 +60,12 @@
bo-attr
bo-attr-data-quicktip-content="i18n(config.collection ? 'config.tooltip.overriddenCollection' : 'config.tooltip.overriddenConfig')"
></coral-icon>
<coral-icon bo-if="!config.overridden && config.inherited" icon="link"
<coral-icon bo-if="!config.overridden && !config.readOnly && config.inherited" icon="link"
data-init="quicktip" data-quicktip-arrow="right" data-quicktip-type="info" role="img" tabindex="0"
bo-attr
bo-attr-data-quicktip-content="i18n(config.collection ? 'config.tooltip.inheritedCollection' : 'config.tooltip.inheritedConfig')"
></coral-icon>
<coral-icon bo-if="!config.overridden && !config.inherited" icon="linkOff"
<coral-icon bo-if="!config.overridden && !config.readOnly && !config.inherited" icon="linkOff"
data-init="quicktip" data-quicktip-arrow="right" data-quicktip-type="info" role="img" tabindex="0"
bo-attr
bo-attr-data-quicktip-content="i18n(config.collection ? 'config.tooltip.notInheritedCollection' : 'config.tooltip.notInheritedConfig')"
Expand Down
6 changes: 3 additions & 3 deletions bundle/src/main/resources/angularjs-partials/pathbrowser.html
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
<div bindonce class="caconfig-pathbrowser" ng-form="inputPathBrowserForm">

<div class="caconfig-if-property-not-overridden-and-not-inherited caconfig-if-config-not-inherited">
<div class="caconfig-if-property-not-overridden-and-not-inherited-and-not-readonly caconfig-if-config-not-inherited">
<foundation-autocomplete>
<coral-overlay foundation-autocomplete-suggestion class="foundation-picker-buttonlist"></coral-overlay>
<coral-taglist foundation-autocomplete-value></coral-taglist>
</foundation-autocomplete>
<div class="coral-Form-errorlabel" bindonce="i18n('validation.required')" ng-show="inputPathBrowserForm.pathBrowser.$error.required" bo-text="i18n('validation.required')"></div>
</div>

<input is="coral-textfield" class="caconfig-if-property-not-overridden-and-not-inherited caconfig-if-config-inherited"
<input is="coral-textfield" class="caconfig-if-property-not-overridden-and-not-inherited-and-not-readonly caconfig-if-config-inherited"
ng-model="property.value"
disabled readonly />

<input is="coral-textfield" class="caconfig-if-property-overridden-or-inherited"
<input is="coral-textfield" class="caconfig-if-property-overridden-or-inherited-or-readonly"
ng-model="property.effectiveValue"
disabled readonly />

Expand Down
Original file line number Diff line number Diff line change
@@ -1,21 +1,21 @@
<div class="caconfig-property-dropdown" bindonce="dropdownReady" ng-model="property.value">
<coral-select class="caconfig-if-property-not-overridden-and-not-inherited caconfig-if-config-not-inherited" bo-id="id"
<coral-select class="caconfig-if-property-not-overridden-and-not-inherited-and-not-readonly caconfig-if-config-not-inherited" bo-id="id"
bo-attr bo-attr-placeholder="i18n('button.choose')">
<coral-select-item ng-repeat="option in dropdownOptions"
bo-value="option.value"
bo-text="option.description">
</coral-select-item>
</coral-select>

<span class="coral-Select coral3-Select caconfig-if-property-not-overridden-and-not-inherited caconfig-if-config-inherited">
<span class="coral-Select coral3-Select caconfig-if-property-not-overridden-and-not-inherited-and-not-readonly caconfig-if-config-inherited">
<button class="coral3-Button coral3-Button--secondary coral3-Button--block coral3-Select-button" disabled readonly>
<coral-icon class="coral3-Icon coral3-Select-openIcon coral3-Icon--chevronDown coral3-Icon--sizeXS" icon="chevronDown" size="XS"></coral-icon>
<span class="coral3-Select-label" bo-if="i18n('button.choose')" bo-text="i18n('button.choose')"></span>
</button>
<coral-taglist class="coral3-Select-tagList caconfig-dummy-taglist"></coral-taglist>
</span>

<span class="coral-Select coral3-Select caconfig-if-property-overridden-or-inherited">
<span class="coral-Select coral3-Select caconfig-if-property-overridden-or-inherited-or-readonly">
<button class="coral3-Button coral3-Button--secondary coral3-Button--block coral3-Select-button" disabled readonly>
<coral-icon class="coral3-Icon coral3-Select-openIcon coral3-Icon--chevronDown coral3-Icon--sizeXS" icon="chevronDown" size="XS"></coral-icon>
<span class="coral3-Select-label" ng-bind="getOptionText(property.effectiveValue)"></span>
Expand Down
Loading

0 comments on commit 50ecfcc

Please sign in to comment.