From 483239e47bef2e147e46d46431c5009898df7cdd Mon Sep 17 00:00:00 2001 From: Konrad Windszus Date: Fri, 31 Jan 2025 20:04:28 +0100 Subject: [PATCH] Dedicated OSGi configuration for granting access to UI No longer leverage PID SlingWebConsoleSecurityProvider as defaults no longer reasonably set in AEMaaCS. Disable action buttons depending on permissions. Clean up HistoryUtils to leverage JcrUtils This closes #781 --- README.md | 4 - .../actool/history/impl/HistoryUtils.java | 27 ++--- .../cq/tools/actool/ui/AcToolUiService.java | 102 +++++++++--------- .../cq/tools/actool/ui/PrincipalUtil.java | 71 ++++++++++++ .../actool/ui/WebConsoleConfigTracker.java | 84 --------------- accesscontroltool-content-package/pom.xml | 2 +- ...q.tools.actool.ui.AcToolUiService.cfg.json | 12 +++ docs/ApplyConfig.md | 5 +- pom.xml | 2 +- 9 files changed, 149 insertions(+), 160 deletions(-) create mode 100644 accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/ui/PrincipalUtil.java delete mode 100644 accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/ui/WebConsoleConfigTracker.java create mode 100644 accesscontroltool-package/src/main/jcr_root-cloud/apps/netcentric/actool/config/biz.netcentric.cq.tools.actool.ui.AcToolUiService.cfg.json diff --git a/README.md b/README.md index db87fe826..de6970525 100644 --- a/README.md +++ b/README.md @@ -48,10 +48,6 @@ You need to setup [Yaml configuration files](docs/Configuration.md) to specify y There are also some [advanced configuration options](docs/AdvancedFeatures.md) supported such as loops, conditional statements and permissions for anonymous. -# User Interface - -There is a Felix Web Console plugin (at `/system/console/actool`) as well as a Touch UI console (at `/mnt/overlay/netcentric/actool/content/overview.html`) to apply configurations and to inspect previous executions of the tool. Additionally there is a [JMX interface](docs/Jmx.md) for some advanced use cases. - # Applying AC Tool Configurations Best practice is to apply AC Tool Configurations using the install hook (or startup hook for Cloud Service) during your project's software package installation. See [applying the ACL entries](docs/ApplyConfig.md) for a full list of options. diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/history/impl/HistoryUtils.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/history/impl/HistoryUtils.java index 2febe078e..f137e5c55 100644 --- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/history/impl/HistoryUtils.java +++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/history/impl/HistoryUtils.java @@ -58,12 +58,12 @@ public class HistoryUtils { public static final String HISTORY_NODE_NAME_PREFIX = "history_"; public static final String NODETYPE_NT_UNSTRUCTURED = "nt:unstructured"; - public static final String ACHISTORY_ROOT_NODE = "achistory"; - public static final String STATISTICS_ROOT_NODE = "var/statistics"; - public static final String ACHISTORY_PATH = "/"+ HistoryUtils.STATISTICS_ROOT_NODE + "/" + HistoryUtils.ACHISTORY_ROOT_NODE; + public static final String ACHISTORY_ROOT_NODE_NAME = "achistory"; + public static final String STATISTICS_ROOT_NODE_PATH = "/var/statistics"; + public static final String ACHISTORY_PATH = HistoryUtils.STATISTICS_ROOT_NODE_PATH + "/" + HistoryUtils.ACHISTORY_ROOT_NODE_NAME; private static final String AC_ROOT_PATH_IN_APPS = "/apps/netcentric"; - public static final String AC_HISTORY_PATH_IN_APPS = AC_ROOT_PATH_IN_APPS + "/" + ACHISTORY_ROOT_NODE; + public static final String AC_HISTORY_PATH_IN_APPS = AC_ROOT_PATH_IN_APPS + "/" + ACHISTORY_ROOT_NODE_NAME; public static final String PROPERTY_TIMESTAMP = "timestamp"; private static final String PROPERTY_MESSAGES = "messages"; @@ -85,10 +85,8 @@ public class HistoryUtils { public static Node getAcHistoryRootNode(final Session session) throws RepositoryException { - final Node rootNode = session.getRootNode(); - Node statisticsRootNode = safeGetNode(rootNode, STATISTICS_ROOT_NODE, NODETYPE_NT_UNSTRUCTURED); - Node acHistoryRootNode = safeGetNode(statisticsRootNode, ACHISTORY_ROOT_NODE, "sling:OrderedFolder"); - return acHistoryRootNode; + Node statisticsRootNode = JcrUtils.getOrCreateByPath(STATISTICS_ROOT_NODE_PATH, NODETYPE_NT_UNSTRUCTURED, session); + return JcrUtils.getOrAddNode(statisticsRootNode, ACHISTORY_ROOT_NODE_NAME, "sling:OrderedFolder"); } /** @@ -139,7 +137,7 @@ public static Node persistHistory(final Session session, } name += AcToolExecutionImpl.TRIGGER_SEPARATOR_IN_NODE_NAME + trigger; - Node newHistoryNode = safeGetNode(acHistoryRootNode, name, NODETYPE_NT_UNSTRUCTURED); + Node newHistoryNode = JcrUtils.getOrAddNode(acHistoryRootNode, name, NODETYPE_NT_UNSTRUCTURED); String path = newHistoryNode.getPath(); setHistoryNodeProperties(newHistoryNode, installLog, trigger); saveLogs(newHistoryNode, installLog); @@ -177,17 +175,6 @@ private static boolean isInStrackTracke(StackTraceElement[] stackTrace, String c return false; } - private static Node safeGetNode(final Node baseNode, final String name, - final String typeToCreate) throws RepositoryException { - if (!baseNode.hasNode(name)) { - LOG.debug("create node: {}", name); - return baseNode.addNode(name, typeToCreate); - - } else { - return baseNode.getNode(name); - } - } - public static void setHistoryNodeProperties(final Node historyNode, PersistableInstallationLogger installLog, String trigger) throws ValueFormatException, VersionException, LockException, ConstraintViolationException, diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/ui/AcToolUiService.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/ui/AcToolUiService.java index 19c20427b..69312195d 100644 --- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/ui/AcToolUiService.java +++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/ui/AcToolUiService.java @@ -23,7 +23,6 @@ import java.text.SimpleDateFormat; import java.util.Arrays; import java.util.HashMap; -import java.util.Iterator; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; @@ -34,21 +33,25 @@ import java.util.stream.Collectors; import javax.jcr.RepositoryException; +import javax.jcr.Session; import javax.jcr.Value; import javax.servlet.ServletException; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; -import org.apache.commons.lang3.ArrayUtils; import org.apache.commons.lang3.StringUtils; import org.apache.felix.webconsole.WebConsoleConstants; -import org.apache.jackrabbit.api.security.user.Group; +import org.apache.jackrabbit.api.JackrabbitSession; import org.apache.jackrabbit.api.security.user.User; import org.apache.jackrabbit.oak.spi.security.principal.EveryonePrincipal; import org.apache.sling.api.SlingHttpServletRequest; +import org.osgi.service.component.annotations.Activate; import org.osgi.service.component.annotations.Component; import org.osgi.service.component.annotations.Reference; import org.osgi.service.component.annotations.ReferencePolicyOption; +import org.osgi.service.metatype.annotations.AttributeDefinition; +import org.osgi.service.metatype.annotations.Designate; +import org.osgi.service.metatype.annotations.ObjectClassDefinition; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -64,6 +67,7 @@ import biz.netcentric.cq.tools.actool.user.UserProcessor; @Component(service = { AcToolUiService.class }) +@Designate(ocd=biz.netcentric.cq.tools.actool.ui.AcToolUiService.Configuration.class) public class AcToolUiService { private static final Logger LOG = LoggerFactory.getLogger(AcToolUiService.class); @@ -88,15 +92,27 @@ public class AcToolUiService { @Reference(policyOption = ReferencePolicyOption.GREEDY) AcInstallationServiceInternal acInstallationService; - @Reference(policyOption = ReferencePolicyOption.GREEDY) - private WebConsoleConfigTracker webConsoleConfig; - @Reference(policyOption = ReferencePolicyOption.GREEDY) private AcHistoryService acHistoryService; + @ObjectClassDefinition(name = "AC Tool UI Service", + description="Service that allows to apply AC Tool configuration and gather status of users/groups and permissions from a Web UI (either Touch UI or Web Console Plugin).") + protected static @interface Configuration { + + @AttributeDefinition(name="Read access", description="Principal names allowed to export all users/groups and permissions in the system. Only leveraged for Touch UI but not for Web Console Plugin.") + String[] readAccessPrincipalNames() default { "administrators", "admin" }; + + @AttributeDefinition(name="Write access", description="Principal names allowed to modify users/groups and permissions in the system via ACTool configuration files. Only leveraged for Touch UI but not for Web Console Plugin.") + String[] writeAccessPrincipalNames() default { "administrators", "admin" }; + } + private final Map countryCodePerName; - public AcToolUiService() { + private final Configuration config; + + @Activate + public AcToolUiService(Configuration config) { + this.config = config; countryCodePerName = new HashMap<>(); for (String iso : Locale.getISOCountries()) { Locale l = new Locale(Locale.ENGLISH.getLanguage(), iso); @@ -108,16 +124,17 @@ protected void doGet(HttpServletRequest req, HttpServletResponse resp, String pa throws ServletException, IOException { if (req.getRequestURI().endsWith(SUFFIX_DUMP_YAML)) { - callWhenAuthorized(req, resp, this::streamDumpToResponse); + callWhenReadAccessGranted(req, resp, this::streamDumpToResponse); } else if (req.getRequestURI().endsWith(SUFFIX_USERS_CSV)) { - callWhenAuthorized(req, resp, this::streamUsersCsvToResponse); + callWhenReadAccessGranted(req, resp, this::streamUsersCsvToResponse); } else { + // everyone is allows to see the UI in general renderUi(req, resp, path, isTouchUi); } } - private void callWhenAuthorized(HttpServletRequest req, HttpServletResponse resp, Consumer responseConsumer) throws IOException { - if (!hasAccessToFelixWebConsole(req)) { + private void callWhenReadAccessGranted(HttpServletRequest req, HttpServletResponse resp, Consumer responseConsumer) throws IOException, ServletException { + if (!isOneOfPrincipalNamesBound(req, config.readAccessPrincipalNames())) { resp.sendError(HttpServletResponse.SC_FORBIDDEN, "You do not have sufficent permissions to export users/groups/permissions"); return; } @@ -127,12 +144,13 @@ private void callWhenAuthorized(HttpServletRequest req, HttpServletResponse resp throw e.getCause(); } } + @SuppressWarnings(/* SonarCloud false positive */ { "javasecurity:S5131" /* response is sent as text/plain, it's not interpreted */, "javasecurity:S5145" /* logging the path is fine */ }) protected void doPost(final HttpServletRequest req, final HttpServletResponse resp) throws IOException, ServletException { - if (!hasAccessToFelixWebConsole(req)) { + if (!isOneOfPrincipalNamesBound(req, config.writeAccessPrincipalNames())) { resp.sendError(HttpServletResponse.SC_FORBIDDEN, "You do not have sufficent permissions to apply the configuration"); return; } @@ -157,45 +175,31 @@ protected void doPost(final HttpServletRequest req, final HttpServletResponse re } /** - * Replicates the logic of the Sling Web Console Security Provider. + * Similar to the logic of the Sling Web Console Security Provider but acting on principal names * @param req the request - * @return {@code true} if the user bound to the given request may also access the Felix Web Console or if we are outside of Sling, {@code false} otherwise + * @param principalNames the principal names to check against + * @return {@code true} if the session bound to the given request is bound to any of the given principal names + * @throws ServletException + * @throws RepositoryException */ - private boolean hasAccessToFelixWebConsole(HttpServletRequest req) { - + private boolean isOneOfPrincipalNamesBound(HttpServletRequest req, String[] principalNames) throws ServletException { if (!(req instanceof SlingHttpServletRequest)) { // outside Sling this is only called by the Felix Web Console, which has its own security layer LOG.debug("Outside Sling no additional security checks are performed!"); return true; } - try { - User requestUser = SlingHttpServletRequest.class.cast(req).getResourceResolver().adaptTo(User.class); - if (requestUser != null) { - if (StringUtils.equals(requestUser.getID(), "admin")) { - LOG.debug("Admin user is allowed to apply AC Tool"); - return true; - } - - if (ArrayUtils.contains(webConsoleConfig.getAllowedUsers(), requestUser.getID())) { - LOG.debug("User {} is allowed to apply AC Tool (allowed users: {})", requestUser.getID(), ArrayUtils.toString(webConsoleConfig.getAllowedUsers())); - return true; - } - - Iterator memberOfIt = requestUser.memberOf(); + Session session = SlingHttpServletRequest.class.cast(req).getResourceResolver().adaptTo(Session.class); + return isOneOfPrincipalNamesBound(JackrabbitSession.class.cast(session), principalNames); + } - while (memberOfIt.hasNext()) { - Group memberOfGroup = memberOfIt.next(); - if (ArrayUtils.contains(webConsoleConfig.getAllowedGroups(), memberOfGroup.getID())) { - LOG.debug("Group {} is allowed to apply AC Tool (allowed groups: {})", memberOfGroup.getID(), ArrayUtils.toString(webConsoleConfig.getAllowedGroups())); - return true; - } - } - } - LOG.debug("Could not get associated user for Sling request"); - return false; - } catch (Exception e) { - throw new IllegalStateException("Could not check if user may apply AC Tool configuration: " + e, e); + private boolean isOneOfPrincipalNamesBound(JackrabbitSession session, String[] principalNames) throws ServletException { + BoundPrincipals boundPrincipals; + try { + boundPrincipals = new BoundPrincipals(JackrabbitSession.class.cast(session)); + } catch (RepositoryException e) { + throw new ServletException("Could not determine bound principals", e); } + return boundPrincipals.containsOneOf(Arrays.asList(principalNames)); } public String getWebConsoleRoot(HttpServletRequest req) { @@ -210,8 +214,8 @@ private void renderUi(HttpServletRequest req, HttpServletResponse resp, String p printCss(isTouchUi, writer); printVersion(writer); - printImportSection(writer, reqParams, path, isTouchUi, getWebConsoleRoot(req)); - printExportSection(writer, reqParams, path, isTouchUi, getWebConsoleRoot(req)); + printImportSection(writer, reqParams, path, isTouchUi, getWebConsoleRoot(req), isOneOfPrincipalNamesBound(req, config.writeAccessPrincipalNames())); + printExportSection(writer, reqParams, path, isTouchUi, getWebConsoleRoot(req), isOneOfPrincipalNamesBound(req, config.readAccessPrincipalNames())); try { printInstallationLogsSection(writer, reqParams, isTouchUi); @@ -425,7 +429,7 @@ private String getExecutionStatusHtml(AcToolExecution acToolExecution) { return acToolExecution.isSuccess() ? "SUCCESS" : "FAILED"; } - private void printImportSection(final HtmlWriter writer, RequestParameters reqParams, String path, boolean isTouchUI, String webConsoleRoot) throws IOException { + private void printImportSection(final HtmlWriter writer, RequestParameters reqParams, String path, boolean isTouchUI, String webConsoleRoot, boolean hasWritePermission) throws IOException { writer.print("
"); writer.openTable("acFormTable"); @@ -473,7 +477,7 @@ private void printImportSection(final HtmlWriter writer, RequestParameters reqPa writer.openTd(); String onClick = "var as=$('#applySpinner');as.show(); var b=$('#applyButton');b.prop('disabled', true); oldL = b.text();b.text(' Applying AC Tool Configuration... ');var f=$('#acForm');var fd=f.serialize();$.post(f.attr('action'), fd).done(function(text){alert(text)}).fail(function(xhr){alert(xhr.status===403?'Permission Denied':'Config could not be applied - check log for errors')}).always(function(text) { " + "as.hide();b.text(oldL);b.prop('disabled', false);location.href='" + PAGE_NAME + "?'+fd; });return false"; - writer.println(""); + writer.println(""); writer.closeTd(); writer.openTd(); writer.println(""); @@ -487,7 +491,7 @@ private void printImportSection(final HtmlWriter writer, RequestParameters reqPa } - private void printExportSection(final HtmlWriter writer, RequestParameters reqParams, String path, boolean isTouchUI, String webConsoleRoot) throws IOException { + private void printExportSection(final HtmlWriter writer, RequestParameters reqParams, String path, boolean isTouchUI, String webConsoleRoot, boolean hasReadPermission) throws IOException { writer.openTable("acExportTable"); writer.tableHeader("Export", 2); writer.tr(); @@ -495,7 +499,7 @@ private void printExportSection(final HtmlWriter writer, RequestParameters reqPa writer.print("Export in AC Tool YAML format. This includes groups and permissions (in form of ACEs)."); writer.closeTd(); writer.openTd(); - writer.println(""); writer.closeTd(); writer.closeTr(); @@ -504,7 +508,7 @@ private void printExportSection(final HtmlWriter writer, RequestParameters reqPa writer.print("Export Users in Admin Console CSV format. This includes non-system users, their profiles and their direct group memberships."); writer.closeTd(); writer.openTd(); - writer.println(""); writer.closeTd(); writer.closeTr(); diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/ui/PrincipalUtil.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/ui/PrincipalUtil.java new file mode 100644 index 000000000..b3e8e26c6 --- /dev/null +++ b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/ui/PrincipalUtil.java @@ -0,0 +1,71 @@ +package biz.netcentric.cq.tools.actool.ui; + +/*- + * #%L + * Access Control Tool Bundle + * %% + * Copyright (C) 2015 - 2024 Cognizant Netcentric + * %% + * 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 + * #L% + */ + +import java.security.Principal; +import java.util.Collection; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; + +import javax.jcr.RepositoryException; + +import org.apache.jackrabbit.api.JackrabbitSession; +import org.apache.jackrabbit.api.security.user.Authorizable; +import org.apache.jackrabbit.api.security.user.AuthorizableTypeException; +import org.apache.jackrabbit.api.security.user.Group; +import org.jetbrains.annotations.NotNull; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + + +/** + * Encapsulates all principals bound to a given session. + * Natively exposed from Oak 1.40 onwards (see OAK-8611). + */ +class BoundPrincipals { + + private static final Logger log = LoggerFactory.getLogger(BoundPrincipals.class); + + private Set boundPrincipals; + + BoundPrincipals(@NotNull JackrabbitSession session) throws RepositoryException { + final String userId = session.getUserID(); + // newer Oak versions expose bound principals via session attribute (https://issues.apache.org/jira/browse/OAK-9415) + boundPrincipals = (Set)session.getAttribute("oak.bound-principals"); + if (boundPrincipals == null) { + boundPrincipals = new HashSet<>(); + Authorizable authorizable = session.getUserManager().getAuthorizable(userId); + if (authorizable == null) { + throw new AuthorizableTypeException("Could not find authorizable for session's user ID " + userId); + } + boundPrincipals.add(authorizable.getPrincipal()); + + Iterator groupIterator = authorizable.memberOf(); + while (groupIterator.hasNext()) { + boundPrincipals.add(groupIterator.next().getPrincipal()); + } + } + } + + public boolean containsOneOf(@NotNull Collection principalNames) { + for (Principal principal : boundPrincipals) { + if (principalNames.contains(principal.getName())) { + return true; + } + } + return false; + } + +} diff --git a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/ui/WebConsoleConfigTracker.java b/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/ui/WebConsoleConfigTracker.java deleted file mode 100644 index 09bf17bdb..000000000 --- a/accesscontroltool-bundle/src/main/java/biz/netcentric/cq/tools/actool/ui/WebConsoleConfigTracker.java +++ /dev/null @@ -1,84 +0,0 @@ -package biz.netcentric.cq.tools.actool.ui; - -/*- - * #%L - * Access Control Tool Bundle - * %% - * Copyright (C) 2015 - 2024 Cognizant Netcentric - * %% - * 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 - * #L% - */ - -import java.io.IOException; -import java.util.Dictionary; - -import org.apache.commons.lang3.ArrayUtils; -import org.apache.sling.commons.osgi.PropertiesUtil; -import org.osgi.service.cm.ConfigurationAdmin; -import org.osgi.service.cm.ConfigurationEvent; -import org.osgi.service.cm.ConfigurationListener; -import org.osgi.service.component.annotations.Activate; -import org.osgi.service.component.annotations.Component; -import org.osgi.service.component.annotations.Reference; -import org.osgi.service.component.annotations.ReferencePolicyOption; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -@Component(service = { WebConsoleConfigTracker.class, ConfigurationListener.class }) -public class WebConsoleConfigTracker implements ConfigurationListener { - - private static final Logger LOG = LoggerFactory.getLogger(WebConsoleConfigTracker.class); - - private static final String CONSOLE_SEC_PROVIDER_PID = "org.apache.sling.extensions.webconsolesecurityprovider.internal.SlingWebConsoleSecurityProvider"; - private static final String CONSOLE_SEC_PROVIDER_USERS_PROP = "users"; - private static final String CONSOLE_SEC_PROVIDER_GROUPS_PROP = "groups"; - - private static final String[] RELEVANT_PIDS = new String[] {CONSOLE_SEC_PROVIDER_PID}; - - @Reference(policyOption = ReferencePolicyOption.GREEDY) - private ConfigurationAdmin configAdmin; - - private String[] allowedUsers = new String[] {}; - private String[] allowedGroups = new String[] {}; - - @Activate - private void updateConfig() { - try { - // make sure that you don't overwrite the binding! - Dictionary webconsoleSecProviderConfig = configAdmin.getConfiguration(CONSOLE_SEC_PROVIDER_PID, null).getProperties(); - if(webconsoleSecProviderConfig != null) { - allowedUsers = PropertiesUtil.toStringArray(webconsoleSecProviderConfig.get(CONSOLE_SEC_PROVIDER_USERS_PROP)); - allowedGroups = PropertiesUtil.toStringArray(webconsoleSecProviderConfig.get(CONSOLE_SEC_PROVIDER_GROUPS_PROP)); - } - if(LOG.isDebugEnabled()) { - LOG.debug("allowedUsers: {} allowedGroups: {}", - ArrayUtils.toString(allowedUsers), - ArrayUtils.toString(allowedGroups)); - } - - } catch (IOException e) { - LOG.warn("Could not update config: "+e, e); - } - } - - @Override - public void configurationEvent(ConfigurationEvent event) { - String pid = event.getPid(); - if(ArrayUtils.contains(RELEVANT_PIDS, pid)) { - updateConfig(); - } - } - - public String[] getAllowedUsers() { - return allowedUsers; - } - - public String[] getAllowedGroups() { - return allowedGroups; - } - -} diff --git a/accesscontroltool-content-package/pom.xml b/accesscontroltool-content-package/pom.xml index 81986ee06..2306ff990 100644 --- a/accesscontroltool-content-package/pom.xml +++ b/accesscontroltool-content-package/pom.xml @@ -25,7 +25,7 @@ accesscontroltool-content-package content-package Access Control Tool Package - Content - Content package of the AC Tool containing the system user and ACLs for it. + Content package of the AC Tool containing the system user and ACLs for it (only relevant for AEM onPrem) diff --git a/accesscontroltool-package/src/main/jcr_root-cloud/apps/netcentric/actool/config/biz.netcentric.cq.tools.actool.ui.AcToolUiService.cfg.json b/accesscontroltool-package/src/main/jcr_root-cloud/apps/netcentric/actool/config/biz.netcentric.cq.tools.actool.ui.AcToolUiService.cfg.json new file mode 100644 index 000000000..0b03f014d --- /dev/null +++ b/accesscontroltool-package/src/main/jcr_root-cloud/apps/netcentric/actool/config/biz.netcentric.cq.tools.actool.ui.AcToolUiService.cfg.json @@ -0,0 +1,12 @@ +{ + "writeAccessPrincipalNames":[ + "administrators", + "admin", + "$[env:aemCloudAdministrators;default=administrators]" + ], + "readAccessPrincipalNames":[ + "administrators", + "admin", + "$[env:aemCloudAdministrators;default=administrators]" + ] +} \ No newline at end of file diff --git a/docs/ApplyConfig.md b/docs/ApplyConfig.md index c30c4c734..6c11c3e8e 100644 --- a/docs/ApplyConfig.md +++ b/docs/ApplyConfig.md @@ -88,7 +88,10 @@ A Felix Web Console UI is available at "Main" -> "AC Tool". The web console prov ### Touch UI -The same interface as available via Web Console is also available via Touch UI at `Tools -> Security -> Netcentric AC Tool` if you are admin on the instance. When using [AEM as a Cloud Service](https://www.adobe.com/marketing/experience-manager/cloud-service.html), the console will be available if you are in the admin group for the AEM env as set up in [adminconsole](https://adminconsole.adobe.com/). +The same interface as available via Web Console is also available via Touch UI at `Tools -> Security -> Netcentric AC Tool`. +It allows viewing the logs of ACTool installations and both applying of ACLs as well as reading of users/ACLs of the system. The latter two require permissions which by default are only granted to the `admin` user and members of the `administrators` group. When using [AEM as a Cloud Service](https://www.adobe.com/marketing/experience-manager/cloud-service.html) in addition also to members of the IMS admin group for the AEM env as set up in [adminconsole](https://adminconsole.adobe.com/). In case you are not having the according permissions the buttons are disabled. + +Adjusting the permissions requires configuring the OSGi config with PID `biz.netcentric.cq.tools.actool.ui.AcToolUiService`. ### JMX diff --git a/pom.xml b/pom.xml index 8ee5cfb34..054f0897f 100644 --- a/pom.xml +++ b/pom.xml @@ -442,7 +442,7 @@ 2.4.0 epl_only_v1 - test/resources/**,it/** + test/resources/**,it/**,**/*.cfg.json