Fixing an issue where it failed to start without xss compat, wasn't serving the js file and didn't create the app folder correctly
diff --git a/pom.xml b/pom.xml
index aa6e3d4..97e097e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,154 +1,162 @@
<?xml version="1.0" encoding="ISO-8859-1"?>
-<!--
- Licensed to the Apache Software Foundation (ASF) under one
- or more contributor license agreements. See the NOTICE file
- distributed with this work for additional information
- regarding copyright ownership. The ASF licenses this file
- to you under the Apache License, Version 2.0 (the
- "License"); you may not use this file except in compliance
- with the License. You may obtain a copy of the License at
-
- http://www.apache.org/licenses/LICENSE-2.0
-
- Unless required by applicable law or agreed to in writing,
- software distributed under the License is distributed on an
- "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- KIND, either express or implied. See the License for the
- specific language governing permissions and limitations
- under the License.
--->
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<!-- Licensed to the Apache Software Foundation (ASF) under one or more contributor
+ license agreements. See the NOTICE file distributed with this work for additional
+ information regarding copyright ownership. The ASF licenses this file to
+ you under the Apache License, Version 2.0 (the "License"); you may not use
+ this file except in compliance with the License. You may obtain a copy of
+ the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required
+ by applicable law or agreed to in writing, software distributed under the
+ License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS
+ OF ANY KIND, either express or implied. See the License for the specific
+ language governing permissions and limitations under the License. -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
- <modelVersion>4.0.0</modelVersion>
- <parent>
- <groupId>org.apache.sling</groupId>
- <artifactId>sling</artifactId>
- <version>30</version>
- <relativePath />
- </parent>
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>sling</artifactId>
+ <version>30</version>
+ <relativePath />
+ </parent>
- <artifactId>org.apache.sling.serviceuser.webconsole</artifactId>
- <packaging>bundle</packaging>
- <version>1.0.1-SNAPSHOT</version>
+ <artifactId>org.apache.sling.serviceuser.webconsole</artifactId>
+ <packaging>bundle</packaging>
+ <version>1.0.0-SNAPSHOT</version>
- <name>Apache Sling Service User Web Console</name>
- <description>
+ <name>Apache Sling Service User Web Console</name>
+ <description>
Provides an OSGi Web Console for creating, updating and viewing Service Users.
</description>
- <scm>
- <connection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-serviceuser-webconsole.git</connection>
- <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-serviceuser-webconsole.git</developerConnection>
- <url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-serviceuser-webconsole.git</url>
- <tag>HEAD</tag>
- </scm>
+ <scm>
+ <connection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-serviceuser-webconsole.git</connection>
+ <developerConnection>scm:git:https://gitbox.apache.org/repos/asf/sling-org-apache-sling-serviceuser-webconsole.git</developerConnection>
+ <url>https://gitbox.apache.org/repos/asf?p=sling-org-apache-sling-serviceuser-webconsole.git</url>
+ <tag>HEAD</tag>
+ </scm>
- <build>
- <plugins>
- <plugin>
- <groupId>org.apache.felix</groupId>
- <artifactId>maven-bundle-plugin</artifactId>
- <extensions>true</extensions>
- <configuration>
- </configuration>
- </plugin>
- <plugin>
- <groupId>org.apache.maven.plugins</groupId>
- <artifactId>maven-javadoc-plugin</artifactId>
- <configuration>
- <excludePackageNames>
- org.apache.sling.serviceuser.console.impl
- </excludePackageNames>
- </configuration>
- </plugin>
- </plugins>
- </build>
- <dependencies>
- <dependency>
- <groupId>org.apache.sling</groupId>
- <artifactId>org.apache.sling.api</artifactId>
- <version>2.5.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.sling</groupId>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Import-Package>
+ <!-- Support XSS API 1.x and 2.x - we use only classes from the API
+ with same signature in both versions -->
+ org.apache.sling.xss;version="[1.0.0,3)",
+ *
+ </Import-Package>
+ </instructions>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <excludePackageNames>
+ org.apache.sling.serviceuser.console.impl
+ </excludePackageNames>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ <dependencies>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.api</artifactId>
+ <version>2.5.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.serviceusermapper</artifactId>
<version>1.4.0</version>
- <scope>provided</scope>
- </dependency>
-
- <!-- JCR Specific items -->
- <dependency>
- <groupId>org.apache.jackrabbit</groupId>
- <artifactId>jackrabbit-api</artifactId>
- <version>2.10.6</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>javax.jcr</groupId>
- <artifactId>jcr</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.sling</groupId>
- <artifactId>org.apache.sling.jcr.base</artifactId>
- <version>2.1.0</version>
- <scope>provided</scope>
- </dependency>
-
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-api</artifactId>
- </dependency>
+ <scope>provided</scope>
+ </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>osgi.core</artifactId>
- </dependency>
- <dependency>
- <groupId>org.osgi</groupId>
- <artifactId>org.osgi.compendium</artifactId>
- <version>4.2.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>javax.servlet</groupId>
- <artifactId>javax.servlet-api</artifactId>
- </dependency>
- <dependency>
- <groupId>org.apache.commons</groupId>
- <artifactId>commons-lang3</artifactId>
- <version>3.3.2</version>
- <scope>provided</scope>
- </dependency>
-
- <!-- Webconsole Dependencies -->
- <dependency>
- <groupId>org.apache.felix</groupId>
- <artifactId>org.apache.felix.webconsole</artifactId>
- <version>4.2.0</version>
- <scope>provided</scope>
- </dependency>
- <dependency>
- <groupId>org.apache.sling</groupId>
- <artifactId>org.apache.sling.xss</artifactId>
- <version>1.0.0</version>
- <scope>provided</scope>
- </dependency>
+ <!-- JCR Specific items -->
+ <dependency>
+ <groupId>org.apache.jackrabbit</groupId>
+ <artifactId>jackrabbit-api</artifactId>
+ <version>2.10.6</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.jcr</groupId>
+ <artifactId>jcr</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.jcr.base</artifactId>
+ <version>2.1.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jackrabbit</groupId>
+ <artifactId>jackrabbit-jcr-commons</artifactId>
+ <version>2.0.0</version>
+ <scope>provided</scope>
+ </dependency>
- <!-- Testing -->
- <dependency>
- <groupId>junit</groupId>
- <artifactId>junit</artifactId>
- </dependency>
- <dependency>
- <groupId>org.slf4j</groupId>
- <artifactId>slf4j-simple</artifactId>
- </dependency>
- <dependency>
- <groupId>org.mockito</groupId>
- <artifactId>mockito-all</artifactId>
- <version>1.9.5</version>
- <scope>test</scope>
- </dependency>
- </dependencies>
+
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>osgi.core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.osgi</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ <version>4.2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>javax.servlet-api</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ <version>3.3.2</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Webconsole Dependencies -->
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.apache.felix.webconsole</artifactId>
+ <version>4.2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.xss</artifactId>
+ <version>1.0.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ <!-- Testing -->
+ <dependency>
+ <groupId>junit</groupId>
+ <artifactId>junit</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.slf4j</groupId>
+ <artifactId>slf4j-simple</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.mockito</groupId>
+ <artifactId>mockito-all</artifactId>
+ <version>1.9.5</version>
+ <scope>test</scope>
+ </dependency>
+ </dependencies>
</project>
diff --git a/src/main/java/org/apache/sling/serviceuser/webconsole/impl/ServiceUserWebConsolePlugin.java b/src/main/java/org/apache/sling/serviceuser/webconsole/impl/ServiceUserWebConsolePlugin.java
index fd9ab5f..5d952fa 100644
--- a/src/main/java/org/apache/sling/serviceuser/webconsole/impl/ServiceUserWebConsolePlugin.java
+++ b/src/main/java/org/apache/sling/serviceuser/webconsole/impl/ServiceUserWebConsolePlugin.java
@@ -21,6 +21,7 @@
import java.io.IOException;
import java.io.PrintWriter;
import java.lang.reflect.Array;
+import java.net.URL;
import java.net.URLEncoder;
import java.security.Principal;
import java.util.ArrayList;
@@ -35,7 +36,6 @@
import java.util.Map.Entry;
import javax.jcr.AccessDeniedException;
-import javax.jcr.Property;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.jcr.UnsupportedRepositoryOperationException;
@@ -56,17 +56,20 @@
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.tuple.ImmutablePair;
import org.apache.commons.lang3.tuple.Pair;
-import org.apache.felix.webconsole.SimpleWebConsolePlugin;
+import org.apache.felix.webconsole.AbstractWebConsolePlugin;
import org.apache.felix.webconsole.WebConsoleConstants;
import org.apache.felix.webconsole.WebConsoleUtil;
+import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.api.security.principal.PrincipalManager;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.sling.api.resource.LoginException;
import org.apache.sling.api.resource.ModifiableValueMap;
import org.apache.sling.api.resource.PersistenceException;
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
import org.apache.sling.api.resource.ResourceUtil;
import org.apache.sling.api.resource.ValueMap;
import org.apache.sling.jcr.base.util.AccessControlUtil;
@@ -93,11 +96,7 @@
WebConsoleConstants.PLUGIN_TITLE + "=" + ServiceUserWebConsolePlugin.TITLE,
WebConsoleConstants.PLUGIN_CATEGORY + "=Sling" })
@SuppressWarnings("serial")
-public class ServiceUserWebConsolePlugin extends SimpleWebConsolePlugin {
-
- public ServiceUserWebConsolePlugin() {
- super(LABEL, TITLE, "Sling", new String[0]);
- }
+public class ServiceUserWebConsolePlugin extends AbstractWebConsolePlugin {
public static final String COMPONENT_NAME = "org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended";
public static final String LABEL = "serviceusers";
@@ -119,6 +118,9 @@
@Reference(policyOption = ReferencePolicyOption.GREEDY)
private XSSAPI xss;
+ @Reference(policyOption = ReferencePolicyOption.GREEDY)
+ private ResourceResolverFactory resolverFactory;
+
@Reference
private ServiceUserMapper mapper;
@@ -137,11 +139,11 @@
config = configs.next();
log.debug("Using existing configuration {}", config);
} else {
- String path = appPath + "/config/" + COMPONENT_NAME + "-" + appPath.substring(appPath.lastIndexOf('/'));
+ String path = appPath + "/config/" + COMPONENT_NAME + "-" + appPath.substring(appPath.lastIndexOf('/') + 1);
log.debug("Creating new configuration {}", path);
config = ResourceUtil.getOrCreateResource(resolver, path, new HashMap<String, Object>() {
{
- put(Property.JCR_PRIMARY_TYPE, "sling:OsgiConfig");
+ put(JcrConstants.JCR_PRIMARYTYPE, "sling:OsgiConfig");
}
}, NodeType.NT_FOLDER, false);
dirty = true;
@@ -223,102 +225,6 @@
}
- private boolean updatePrivileges(HttpServletRequest request, ResourceResolver resolver) {
-
- List<Pair<String, String>> privileges = this.getPrivileges(request);
- String name = getParameter(request, PN_NAME, "");
-
- List<String> currentPolicies = new ArrayList<String>();
- findACLs(resolver, name, currentPolicies);
- for (int i = 0; i < currentPolicies.size(); i++) {
- String path = StringUtils.substringBefore(currentPolicies.get(i), "/rep:policy");
- currentPolicies.set(i, StringUtils.isNotBlank(path) ? path : "/");
- }
- log.debug("Loaded current policy paths: {}", currentPolicies);
-
- Map<String, List<String>> toSet = new HashMap<String, List<String>>();
- for (Pair<String, String> privilege : privileges) {
- if (!toSet.containsKey(privilege.getKey())) {
- toSet.put(privilege.getKey(), new ArrayList<String>());
- }
- toSet.get(privilege.getKey()).add(privilege.getValue());
- }
- log.debug("Loaded updated policy paths: {}", currentPolicies);
-
- String lastEntry = null;
-
- try {
-
- Session session = resolver.adaptTo(Session.class);
- AccessControlManager accessManager = session.getAccessControlManager();
- PrincipalManager principalManager = AccessControlUtil.getPrincipalManager(session);
-
- for (Entry<String, List<String>> pol : toSet.entrySet()) {
- lastEntry = pol.getKey();
- currentPolicies.remove(pol.getKey());
- log.debug("Updating policies for {}", pol.getKey());
-
- AccessControlPolicy[] policies = accessManager.getPolicies(pol.getKey());
- List<String> toRemove = new ArrayList<String>();
- for (AccessControlPolicy p : policies) {
- if (p instanceof AccessControlList) {
- AccessControlList policy = (AccessControlList) p;
- for (AccessControlEntry entry : policy.getAccessControlEntries()) {
- Principal prin = entry.getPrincipal();
- if (prin.getName().equals(name)) {
- for (Privilege privilege : entry.getPrivileges()) {
- if (!pol.getValue().contains(privilege.getName())) {
- log.debug("Removing privilege {}", privilege);
- toRemove.add(privilege.getName());
- }
- }
- }
- }
- }
- }
- Principal principal = principalManager.getPrincipal(name);
- AccessControlUtil.replaceAccessControlEntry(session, pol.getKey(), principal,
- pol.getValue().toArray(new String[pol.getValue().size()]), new String[0],
- toRemove.toArray(new String[toRemove.size()]), null);
- }
- session.save();
-
- for (String oldPolicy : currentPolicies) {
- boolean removed = false;
- log.debug("Removing policy for {}", oldPolicy);
- AccessControlPolicy[] policies = accessManager.getPolicies(oldPolicy);
- AccessControlEntry toRemove = null;
- for (AccessControlPolicy p : policies) {
- if (p instanceof AccessControlList) {
- AccessControlList policy = (AccessControlList) p;
- for (AccessControlEntry entry : policy.getAccessControlEntries()) {
- Principal prin = entry.getPrincipal();
- if (prin.getName().equals(name)) {
- toRemove = entry;
- break;
- }
- }
- if (toRemove != null) {
- removed = true;
- policy.removeAccessControlEntry(toRemove);
- accessManager.setPolicy(oldPolicy, policy);
- session.save();
- log.debug("Removed access control entry {}", toRemove);
- }
- }
- }
- if (!removed) {
- log.warn("No policy found for {}", oldPolicy);
- }
- }
- } catch (RepositoryException e) {
- log.error("Exception updating principals with {}, failed on {}", toSet, lastEntry, e);
- return false;
- }
-
- return true;
- }
-
private List<String> extractPrincipals(Mapping mapping) {
List<String> principals = new ArrayList<String>();
String userName = mapping.map(mapping.getServiceName(), mapping.getSubServiceName());
@@ -404,6 +310,11 @@
return bundles;
}
+ @Override
+ public String getLabel() {
+ return LABEL;
+ }
+
private Resource getOrCreateServiceUser(HttpServletRequest request, ResourceResolver resolver) {
final String name = getParameter(request, PN_NAME, "");
@@ -450,12 +361,86 @@
return defaultValue;
}
+ private List<Pair<String, String>> getPrivileges(HttpServletRequest request) {
+ List<Pair<String, String>> privileges = new ArrayList<Pair<String, String>>();
+ List<String> params = Collections.list(request.getParameterNames());
+
+ for (String param : params) {
+ if (param.startsWith("acl-path-")) {
+ String path = request.getParameter(param);
+ String privilege = request.getParameter(param.replace("-path-", "-privilege-"));
+ if (StringUtils.isNotBlank(path) && StringUtils.isNotBlank(privilege)) {
+ privileges.add(new ImmutablePair<String, String>(path, privilege));
+ } else {
+ log.warn("Unable to load ACL due to missing value {}={}", path, privilege);
+ }
+ }
+ }
+
+ return privileges;
+ }
+
+ @SuppressWarnings("deprecation")
private ResourceResolver getResourceResolver(HttpServletRequest request) {
- ResourceResolver resolver = (ResourceResolver) request
- .getAttribute("org.apache.sling.auth.core.ResourceResolver");
+ ResourceResolver resolver = null;
+ try {
+ resolver = (ResourceResolver) request.getAttribute("org.apache.sling.auth.core.ResourceResolver");
+ if (resolver == null) {
+ log.warn("Resource resolver not available in request, falling back to adminstrative resource resolver");
+ resolver = resolverFactory.getAdministrativeResourceResolver(null);
+ }
+ } catch (LoginException le) {
+ throw new RuntimeException(
+ "Unable to get Administrative Resource Resolver, add the bundle org.apache.sling.serviceuser.webconsole in the Apache Sling Login Admin Whitelist",
+ le);
+ }
return resolver;
}
+ /**
+ * Called internally by {@link AbstractWebConsolePlugin} to load resources.
+ *
+ * This particular implementation depends on the label. As example, if the
+ * plugin is accessed as <code>/system/console/abc</code>, and the plugin
+ * resources are accessed like
+ * <code>/system/console/abc/res/logo.gif</code>, the code here will try
+ * load resource <code>/res/logo.gif</code> from the bundle, providing the
+ * plugin.
+ *
+ *
+ * @param path
+ * the path to read.
+ * @return the URL of the resource or <code>null</code> if not found.
+ */
+ protected URL getResource(String path) {
+ String base = "/" + LABEL + "/";
+ return (path != null && path.startsWith(base)) ? getClass().getResource(path.substring(base.length() - 1))
+ : null;
+ }
+
+ private String[] getSupportedPrivileges(HttpServletRequest request) {
+ String[] names = null;
+ try {
+ ResourceResolver resolver = getResourceResolver(request);
+ Session session = resolver.adaptTo(Session.class);
+ AccessControlManager accessControl = session.getAccessControlManager();
+ Privilege[] privileges = accessControl.getSupportedPrivileges("/");
+ names = new String[privileges.length];
+ for (int i = 0; i < privileges.length; i++) {
+ names[i] = privileges[i].getName();
+ }
+ Arrays.sort(names);
+ } catch (RepositoryException re) {
+ log.error("Exception loading Supported Privileges", re);
+ }
+ return names;
+ }
+
+ @Override
+ public String getTitle() {
+ return TITLE;
+ }
+
private boolean hasPrincipal(Mapping map, String name) {
Iterable<String> principals = map.mapPrincipals(map.getServiceName(), map.getSubServiceName());
if (principals != null) {
@@ -533,6 +518,48 @@
}
+ private void printPrivilegeSelect(PrintWriter pw, String label, List<Pair<String, String>> privileges,
+ String[] supportedPrivileges, String alertMessage) {
+ pw.print("<td style='width:20%'>");
+ pw.print(xss.encodeForHTMLAttr(label));
+ pw.println("</td>");
+ pw.print("<td><table class=\"repeating-container\" style=\"width: 100%\" data-length=\"" + privileges.size()
+ + "\"><tr><td>Path</td><td>Privilege</td><td></td>");
+
+ int idx = 0;
+ for (Pair<String, String> privilege : privileges) {
+ pw.print("</tr><tr class=\"repeating-item\"><td>");
+
+ pw.print("<input type=\"text\" name=\"acl-path-" + idx + "\" value='");
+ pw.print(xss.encodeForHTMLAttr(StringUtils.defaultString(privilege.getKey())));
+ pw.print("' style='width:100%' />");
+
+ pw.print("</td><td>");
+
+ pw.print("<input type=\"text\" list=\"data-privileges\" name=\"acl-privilege-" + idx + "\" value='");
+ pw.print(xss.encodeForHTMLAttr(StringUtils.defaultString(privilege.getValue())));
+ pw.print("' style='width:100%' />");
+
+ pw.print("</td><td>");
+
+ pw.print("<input type=\"button\" value=\" - \" class=\"repeating-remove\" /></td>");
+ }
+ pw.print("</tr></table>");
+
+ pw.print("<input type=\"button\" value=\" + \" class=\"repeating-add\" />");
+
+ pw.print("<datalist id=\"data-privileges\">");
+ for (String option : supportedPrivileges) {
+ pw.print("<option");
+ pw.print(">");
+ pw.print(xss.encodeForHTMLAttr(option));
+ pw.print("</option>");
+ }
+ pw.print("</datalist><script src=\"/system/console/serviceusers/res/ui/serviceusermanager.js\"></script>");
+ infoDiv(pw, alertMessage);
+ pw.println("</td>");
+ }
+
private void printServiceUserDetails(HttpServletRequest request, PrintWriter pw)
throws AccessDeniedException, UnsupportedRepositoryOperationException, RepositoryException {
String name = getParameter(request, PN_USER, "");
@@ -676,44 +703,6 @@
}
}
- private List<Pair<String, String>> getPrivileges(HttpServletRequest request) {
- List<Pair<String, String>> privileges = new ArrayList<Pair<String, String>>();
- List<String> params = Collections.list(request.getParameterNames());
-
- for (String param : params) {
- if (param.startsWith("acl-path-")) {
- String path = request.getParameter(param);
- String privilege = request.getParameter(param.replace("-path-", "-privilege-"));
- if (StringUtils.isNotBlank(path) && StringUtils.isNotBlank(privilege)) {
- privileges.add(new ImmutablePair<String, String>(path, privilege));
- } else {
- log.warn("Unable to load ACL due to missing value {}={}", path, privilege);
- }
- }
- }
-
- return privileges;
- }
-
- private String[] getSupportedPrivileges(HttpServletRequest request) {
- String[] names = null;
- try {
- ResourceResolver resolver = getResourceResolver(request);
- Session session = resolver.adaptTo(Session.class);
- AccessControlManager accessControl = session.getAccessControlManager();
- Privilege[] privileges = accessControl.getSupportedPrivileges("/");
- names = new String[privileges.length];
- for (int i = 0; i < privileges.length; i++) {
- names[i] = privileges[i].getName();
- }
- Arrays.sort(names);
- } catch (RepositoryException re) {
- log.error("Exception loading Supported Privileges", re);
- }
- return names;
-
- }
-
@Override
protected void renderContent(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
@@ -745,48 +734,6 @@
}
}
- private void printPrivilegeSelect(PrintWriter pw, String label, List<Pair<String, String>> privileges,
- String[] supportedPrivileges, String alertMessage) {
- pw.print("<td style='width:20%'>");
- pw.print(xss.encodeForHTMLAttr(label));
- pw.println("</td>");
- pw.print("<td><table class=\"repeating-container\" style=\"width: 100%\" data-length=\"" + privileges.size()
- + "\"><tr><td>Path</td><td>Privilege</td><td></td>");
-
- int idx = 0;
- for (Pair<String, String> privilege : privileges) {
- pw.print("</tr><tr class=\"repeating-item\"><td>");
-
- pw.print("<input type=\"text\" name=\"acl-path-" + idx + "\" value='");
- pw.print(xss.encodeForHTMLAttr(StringUtils.defaultString(privilege.getKey())));
- pw.print("' style='width:100%' />");
-
- pw.print("</td><td>");
-
- pw.print("<input type=\"text\" list=\"data-privileges\" name=\"acl-privilege-" + idx + "\" value='");
- pw.print(xss.encodeForHTMLAttr(StringUtils.defaultString(privilege.getValue())));
- pw.print("' style='width:100%' />");
-
- pw.print("</td><td>");
-
- pw.print("<input type=\"button\" value=\" - \" class=\"repeating-remove\" /></td>");
- }
- pw.print("</tr></table>");
-
- pw.print("<input type=\"button\" value=\" + \" class=\"repeating-add\" />");
-
- pw.print("<datalist id=\"data-privileges\">");
- for (String option : supportedPrivileges) {
- pw.print("<option");
- pw.print(">");
- pw.print(xss.encodeForHTMLAttr(option));
- pw.print("</option>");
- }
- pw.print("</datalist><script src=\"/system/console/serviceusers/res/ui/serviceusermanager.js\"></script>");
- infoDiv(pw, alertMessage);
- pw.println("</td>");
- }
-
private void selectField(PrintWriter pw, String label, String fieldName, String value, Collection<String> options,
String... alertMessages) {
pw.print("<td style='width:20%'>");
@@ -902,4 +849,100 @@
pw.println("</td>");
}
+ private boolean updatePrivileges(HttpServletRequest request, ResourceResolver resolver) {
+
+ List<Pair<String, String>> privileges = this.getPrivileges(request);
+ String name = getParameter(request, PN_NAME, "");
+
+ List<String> currentPolicies = new ArrayList<String>();
+ findACLs(resolver, name, currentPolicies);
+ for (int i = 0; i < currentPolicies.size(); i++) {
+ String path = StringUtils.substringBefore(currentPolicies.get(i), "/rep:policy");
+ currentPolicies.set(i, StringUtils.isNotBlank(path) ? path : "/");
+ }
+ log.debug("Loaded current policy paths: {}", currentPolicies);
+
+ Map<String, List<String>> toSet = new HashMap<String, List<String>>();
+ for (Pair<String, String> privilege : privileges) {
+ if (!toSet.containsKey(privilege.getKey())) {
+ toSet.put(privilege.getKey(), new ArrayList<String>());
+ }
+ toSet.get(privilege.getKey()).add(privilege.getValue());
+ }
+ log.debug("Loaded updated policy paths: {}", currentPolicies);
+
+ String lastEntry = null;
+
+ try {
+
+ Session session = resolver.adaptTo(Session.class);
+ AccessControlManager accessManager = session.getAccessControlManager();
+ PrincipalManager principalManager = AccessControlUtil.getPrincipalManager(session);
+
+ for (Entry<String, List<String>> pol : toSet.entrySet()) {
+ lastEntry = pol.getKey();
+ currentPolicies.remove(pol.getKey());
+ log.debug("Updating policies for {}", pol.getKey());
+
+ AccessControlPolicy[] policies = accessManager.getPolicies(pol.getKey());
+ List<String> toRemove = new ArrayList<String>();
+ for (AccessControlPolicy p : policies) {
+ if (p instanceof AccessControlList) {
+ AccessControlList policy = (AccessControlList) p;
+ for (AccessControlEntry entry : policy.getAccessControlEntries()) {
+ Principal prin = entry.getPrincipal();
+ if (prin.getName().equals(name)) {
+ for (Privilege privilege : entry.getPrivileges()) {
+ if (!pol.getValue().contains(privilege.getName())) {
+ log.debug("Removing privilege {}", privilege);
+ toRemove.add(privilege.getName());
+ }
+ }
+ }
+ }
+ }
+ }
+ Principal principal = principalManager.getPrincipal(name);
+ AccessControlUtil.replaceAccessControlEntry(session, pol.getKey(), principal,
+ pol.getValue().toArray(new String[pol.getValue().size()]), new String[0],
+ toRemove.toArray(new String[toRemove.size()]), null);
+ }
+ session.save();
+
+ for (String oldPolicy : currentPolicies) {
+ boolean removed = false;
+ log.debug("Removing policy for {}", oldPolicy);
+ AccessControlPolicy[] policies = accessManager.getPolicies(oldPolicy);
+ AccessControlEntry toRemove = null;
+ for (AccessControlPolicy p : policies) {
+ if (p instanceof AccessControlList) {
+ AccessControlList policy = (AccessControlList) p;
+ for (AccessControlEntry entry : policy.getAccessControlEntries()) {
+ Principal prin = entry.getPrincipal();
+ if (prin.getName().equals(name)) {
+ toRemove = entry;
+ break;
+ }
+ }
+ if (toRemove != null) {
+ removed = true;
+ policy.removeAccessControlEntry(toRemove);
+ accessManager.setPolicy(oldPolicy, policy);
+ session.save();
+ log.debug("Removed access control entry {}", toRemove);
+ }
+ }
+ }
+ if (!removed) {
+ log.warn("No policy found for {}", oldPolicy);
+ }
+ }
+ } catch (RepositoryException e) {
+ log.error("Exception updating principals with {}, failed on {}", toSet, lastEntry, e);
+ return false;
+ }
+
+ return true;
+ }
+
}