SLING-11254 Make additional authorization on HTTP scan endpoint mandatory
use Commons Permissions
diff --git a/pom.xml b/pom.xml
index 56f083d..86008cd 100644
--- a/pom.xml
+++ b/pom.xml
@@ -283,6 +283,12 @@
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.commons.permissions</artifactId>
+ <version>1.0.0-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.event</artifactId>
<version>4.2.10</version>
<scope>provided</scope>
diff --git a/src/main/java/org/apache/sling/clam/http/internal/ClamJcrScanServlet.java b/src/main/java/org/apache/sling/clam/http/internal/ClamJcrScanServlet.java
index 3cbc9f5..4cd9bb1 100644
--- a/src/main/java/org/apache/sling/clam/http/internal/ClamJcrScanServlet.java
+++ b/src/main/java/org/apache/sling/clam/http/internal/ClamJcrScanServlet.java
@@ -19,8 +19,6 @@
package org.apache.sling.clam.http.internal;
import java.io.IOException;
-import java.util.Arrays;
-import java.util.List;
import java.util.Set;
import java.util.regex.Pattern;
@@ -34,6 +32,7 @@
import org.apache.sling.api.resource.Resource;
import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.clam.jcr.NodeDescendingJcrPropertyDigger;
+import org.apache.sling.commons.permissions.PermissionsService;
import org.jetbrains.annotations.NotNull;
import org.osgi.framework.Constants;
import org.osgi.service.component.annotations.Activate;
@@ -47,7 +46,6 @@
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
-import static org.apache.sling.clam.http.internal.RequestUtil.isAuthorized;
import static org.apache.sling.clam.http.internal.RequestUtil.maxDepth;
import static org.apache.sling.clam.http.internal.RequestUtil.maxLength;
import static org.apache.sling.clam.http.internal.RequestUtil.path;
@@ -78,6 +76,12 @@
)
private volatile NodeDescendingJcrPropertyDigger digger;
+ @Reference(
+ policy = ReferencePolicy.DYNAMIC,
+ policyOption = ReferencePolicyOption.GREEDY
+ )
+ private volatile PermissionsService permissionsService;
+
private ClamJcrScanServletConfiguration configuration;
private Pattern pattern;
@@ -122,10 +126,9 @@
@Override
@SuppressWarnings({"checkstyle:IllegalCatch", "checkstyle:ReturnCount", "checkstyle:ExecutableStatementCount"})
protected void doPost(@NotNull final SlingHttpServletRequest request, @NotNull final SlingHttpServletResponse response) throws ServletException, IOException {
- final List<String> groups = Arrays.asList(configuration.scan_authorized_groups());
boolean isAuthorized = false;
try {
- isAuthorized = isAuthorized(request, groups);
+ isAuthorized = permissionsService.hasPermission(request.getUserPrincipal(), configuration.scan_permission());
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
diff --git a/src/main/java/org/apache/sling/clam/http/internal/ClamJcrScanServletConfiguration.java b/src/main/java/org/apache/sling/clam/http/internal/ClamJcrScanServletConfiguration.java
index be42e58..1605d13 100644
--- a/src/main/java/org/apache/sling/clam/http/internal/ClamJcrScanServletConfiguration.java
+++ b/src/main/java/org/apache/sling/clam/http/internal/ClamJcrScanServletConfiguration.java
@@ -42,10 +42,10 @@
String[] sling_auth_requirements() default {"/system/clam-jcr-scan"};
@AttributeDefinition(
- name = "scan authorized groups",
- description = "User groups authorized for scanning"
+ name = "scan permission",
+ description = "Permission required for scanning"
)
- String[] scan_authorized_groups() default {"sling-clam-scan"};
+ String scan_permission() default "sling/clam/scan";
@AttributeDefinition(
name = "default property types",
diff --git a/src/main/java/org/apache/sling/clam/http/internal/RequestUtil.java b/src/main/java/org/apache/sling/clam/http/internal/RequestUtil.java
index dcb3ddb..c29096f 100644
--- a/src/main/java/org/apache/sling/clam/http/internal/RequestUtil.java
+++ b/src/main/java/org/apache/sling/clam/http/internal/RequestUtil.java
@@ -19,13 +19,9 @@
package org.apache.sling.clam.http.internal;
import java.util.Arrays;
-import java.util.Collection;
-import java.util.Iterator;
import java.util.Set;
import java.util.regex.Pattern;
-import org.apache.jackrabbit.api.security.user.Authorizable;
-import org.apache.jackrabbit.api.security.user.Group;
import org.apache.sling.api.SlingHttpServletRequest;
import org.jetbrains.annotations.NotNull;
@@ -104,20 +100,4 @@
}
}
- @SuppressWarnings({"java:S112", "checkstyle:ReturnCount"})
- static boolean isAuthorized(@NotNull final SlingHttpServletRequest request, @NotNull final Collection<String> authorizedGroups) throws Exception {
- final Authorizable authorizable = request.getResourceResolver().adaptTo(Authorizable.class);
- if (authorizable == null) {
- return false;
- }
- final Iterator<Group> groups = authorizable.memberOf();
- while (groups.hasNext()) {
- final String id = groups.next().getID();
- if (authorizedGroups.contains(id)) {
- return true;
- }
- }
- return false;
- }
-
}
diff --git a/src/test/java/org/apache/sling/clam/it/tests/ClamJcrScanServletIT.java b/src/test/java/org/apache/sling/clam/it/tests/ClamJcrScanServletIT.java
index 6811a51..d95c227 100644
--- a/src/test/java/org/apache/sling/clam/it/tests/ClamJcrScanServletIT.java
+++ b/src/test/java/org/apache/sling/clam/it/tests/ClamJcrScanServletIT.java
@@ -38,6 +38,7 @@
import static io.restassured.RestAssured.given;
import static java.util.concurrent.TimeUnit.MINUTES;
import static java.util.concurrent.TimeUnit.SECONDS;
+import static org.apache.sling.testing.paxexam.SlingOptions.slingCommonsPermissionsSling;
import static org.apache.sling.testing.paxexam.SlingOptions.slingJcrJackrabbitUsermanager;
import static org.apache.sling.testing.paxexam.SlingOptions.slingResourcePresence;
import static org.apache.sling.testing.paxexam.SlingOptions.slingStarterContent;
@@ -55,6 +56,14 @@
private static final String URL_TEMPLATE = "http://localhost:%s/system/clam-jcr-scan";
+ private static final String AUTHORIZED_USER_USERNAME = "alice";
+
+ private static final String AUTHORIZED_USER_PASSWORD = "foo";
+
+ private static final String UNAUTHORIZED_USER_USERNAME = "bob";
+
+ private static final String UNAUTHORIZED_USER_PASSWORD = "bar";
+
@Configuration
public Option[] configuration() {
return options(
@@ -65,7 +74,27 @@
.put("path", "/content/starter/img/sling-logo.svg")
.asOption(),
slingStarterContent(),
- slingJcrJackrabbitUsermanager()
+ slingJcrJackrabbitUsermanager(),
+ factoryConfiguration("org.apache.sling.jcr.repoinit.RepositoryInitializer")
+ .put("scripts", new String[]{
+ "create group sling-clam-scan\n" +
+ String.format("create user %s with password %s\n", UNAUTHORIZED_USER_USERNAME, UNAUTHORIZED_USER_PASSWORD) +
+ String.format("create user %s with password %s\n", AUTHORIZED_USER_USERNAME, AUTHORIZED_USER_PASSWORD) +
+ String.format("add %s to group sling-clam-scan\n", AUTHORIZED_USER_USERNAME) +
+ "create path (sling:Folder) /libs/sling/permissions/sling/clam/scan\n" +
+ "set ACL for sling-clam-scan\nallow jcr:read on /libs/sling/permissions/sling/clam/scan\nend\n"
+ })
+ .asOption(),
+ // Sling Commons Permissions Sling
+ slingCommonsPermissionsSling(),
+ factoryConfiguration("org.apache.sling.commons.permissions.sling.internal.SlingPermissionsService")
+ .put("path", "/libs/sling/permissions")
+ .asOption(),
+ factoryConfiguration("org.apache.sling.jcr.base.internal.LoginAdminWhitelist.fragment")
+ .put("whitelist.bundles", new String[]{
+ "org.apache.sling.commons.permissions.sling"
+ })
+ .asOption()
);
}
@@ -84,7 +113,7 @@
final String url = String.format(URL_TEMPLATE, httpPort());
given()
.auth()
- .basic(ADMIN_USERNAME, ADMIN_PASSWORD)
+ .basic(UNAUTHORIZED_USER_USERNAME, UNAUTHORIZED_USER_PASSWORD)
.param("path", "/content/starter")
.when()
.post(url)
@@ -97,7 +126,7 @@
final String url = String.format(URL_TEMPLATE, httpPort());
given()
.auth()
- .basic(USER_USERNAME, USER_PASSWORD)
+ .basic(AUTHORIZED_USER_USERNAME, AUTHORIZED_USER_PASSWORD)
.param("path", "/content/starter")
.when()
.post(url)
@@ -113,7 +142,7 @@
final String url = String.format(URL_TEMPLATE, httpPort());
given()
.auth()
- .basic(USER_USERNAME, USER_PASSWORD)
+ .basic(AUTHORIZED_USER_USERNAME, AUTHORIZED_USER_PASSWORD)
.param("path", "/content/starter")
.when()
.post(url)
diff --git a/src/test/java/org/apache/sling/clam/it/tests/ClamTestSupport.java b/src/test/java/org/apache/sling/clam/it/tests/ClamTestSupport.java
index d3089e6..38ca07f 100644
--- a/src/test/java/org/apache/sling/clam/it/tests/ClamTestSupport.java
+++ b/src/test/java/org/apache/sling/clam/it/tests/ClamTestSupport.java
@@ -40,6 +40,7 @@
import static org.apache.sling.testing.paxexam.SlingOptions.awaitility;
import static org.apache.sling.testing.paxexam.SlingOptions.restassured;
import static org.apache.sling.testing.paxexam.SlingOptions.slingCommonsClam;
+import static org.apache.sling.testing.paxexam.SlingOptions.slingCommonsPermissions;
import static org.apache.sling.testing.paxexam.SlingOptions.slingEvent;
import static org.apache.sling.testing.paxexam.SlingOptions.slingQuickstartOakTar;
import static org.apache.sling.testing.paxexam.SlingOptions.testcontainers;
@@ -65,10 +66,6 @@
static final String ADMIN_PASSWORD = "admin";
- static final String USER_USERNAME = "bob";
-
- static final String USER_PASSWORD = "foo";
-
protected ModifiableCompositeOption baseConfiguration() {
return composite(
super.baseConfiguration(),
@@ -78,14 +75,13 @@
factoryConfiguration("org.apache.sling.jcr.repoinit.RepositoryInitializer")
.put("scripts", new String[]{"create service user sling-clam with path system/sling\ncreate path (sling:Folder) /var/clam/results(sling:OrderedFolder)\nset principal ACL for sling-clam\nallow jcr:read on /\nallow rep:write on /var/clam\nend"})
.asOption(),
- factoryConfiguration("org.apache.sling.jcr.repoinit.RepositoryInitializer")
- .put("scripts", new String[]{"create user bob with password foo\ncreate group sling-clam-scan\nadd bob to group sling-clam-scan"})
- .asOption(),
factoryConfiguration("org.apache.sling.serviceusermapping.impl.ServiceUserMapperImpl.amended")
.put("user.mapping", new String[]{"org.apache.sling.clam=[sling-clam]", "org.apache.sling.clam:result-writer=[sling-clam]"})
.asOption(),
// Sling Commons Clam
slingCommonsClam(),
+ // Sling Commons Permissions
+ slingCommonsPermissions(),
// testing
newConfiguration("org.apache.sling.jcr.base.internal.LoginAdminWhitelist")
.put("whitelist.bundles.regexp", "PAXEXAM-PROBE-.*")