This is an automated email from the ASF dual-hosted git repository.
enorman pushed a commit to branch master
in repository
https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-jackrabbit-accessmanager.git
The following commit(s) were added to refs/heads/master by this push:
new daf66b0 SLING-11271 servlet to get json for an ACE or Effective ACE
(#7)
daf66b0 is described below
commit daf66b026293560552aae49a13e84d6b915cfb88
Author: Eric Norman <[email protected]>
AuthorDate: Fri Apr 22 11:05:47 2022 -0700
SLING-11271 servlet to get json for an ACE or Effective ACE (#7)
---
pom.xml | 2 +-
.../sling/jcr/jackrabbit/accessmanager/GetAce.java | 48 ++++
.../jackrabbit/accessmanager/GetEffectiveAce.java | 48 ++++
.../jackrabbit/accessmanager/impl/JsonConvert.java | 167 +++++++++++
.../post/AbstractAccessGetServlet.java | 187 +++++++++++++
.../accessmanager/post/AbstractGetAceServlet.java | 89 ++++++
.../accessmanager/post/AbstractGetAclServlet.java | 201 ++------------
.../accessmanager/post/GetAceServlet.java | 112 ++++++++
.../accessmanager/post/GetEffectiveAceServlet.java | 112 ++++++++
.../accessmanager/impl/JsonConvertTest.java | 309 +++++++++++++++++++++
.../jcr/jackrabbit/accessmanager/it/GetAceIT.java | 138 +++++++++
.../accessmanager/it/GetAceServiceIT.java | 225 +++++++++++++++
.../jcr/jackrabbit/accessmanager/it/GetAclIT.java | 23 ++
.../jcr/jackrabbit/accessmanager/it/GetEaceIT.java | 137 +++++++++
.../accessmanager/it/GetEaceServiceIT.java | 225 +++++++++++++++
15 files changed, 1851 insertions(+), 172 deletions(-)
diff --git a/pom.xml b/pom.xml
index 5c64daf..879e373 100644
--- a/pom.xml
+++ b/pom.xml
@@ -29,7 +29,7 @@
<artifactId>org.apache.sling.jcr.jackrabbit.accessmanager</artifactId>
<version>3.0.11-SNAPSHOT</version>
- <name>Apache Sling JCR Jackrabbit Access Manager </name>
+ <name>Apache Sling JCR Jackrabbit Access Manager</name>
<description>
Provides POST operations for JCR Jackrabbit Access Management
</description>
diff --git
a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/GetAce.java
b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/GetAce.java
new file mode 100644
index 0000000..cef013b
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/GetAce.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.json.JsonObject;
+
+/**
+ * The <code>GetAce</code> service api.
+ * <p>
+ * This interface is not intended to be implemented by bundles. It is
+ * implemented by this bundle and may be used by client bundles.
+ * </p>
+ */
+public interface GetAce {
+
+ /**
+ * Gets the declared access control entry for a resource and principal
+ *
+ * @param jcrSession the JCR session of the user updating the user
+ * @param resourcePath The path of the resource to get the ACE for
(required)
+ * @param principalId the principal to get the ACE for (required)
+ * @return the ACE as a JSON object
+ * @throws RepositoryException if any errors reading the information
+ */
+ JsonObject getAce(Session jcrSession,
+ String resourcePath,
+ String principalId
+ ) throws RepositoryException;
+
+}
diff --git
a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/GetEffectiveAce.java
b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/GetEffectiveAce.java
new file mode 100644
index 0000000..8cf0103
--- /dev/null
+++
b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/GetEffectiveAce.java
@@ -0,0 +1,48 @@
+/*
+ * 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.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.json.JsonObject;
+
+/**
+ * The <code>GetEffectiveAce</code> service api.
+ * <p>
+ * This interface is not intended to be implemented by bundles. It is
+ * implemented by this bundle and may be used by client bundles.
+ * </p>
+ */
+public interface GetEffectiveAce {
+
+ /**
+ * Gets the effective access control entry for a resource and principal
+ *
+ * @param jcrSession the JCR session of the user updating the user
+ * @param resourcePath The path of the resource to get the ACE for
(required)
+ * @param principalId the principal to get the ACE for (required)
+ * @return the ACE as a JSON object
+ * @throws RepositoryException if any errors reading the information
+ */
+ JsonObject getEffectiveAce(Session jcrSession,
+ String resourcePath,
+ String principalId
+ ) throws RepositoryException;
+
+}
diff --git
a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/impl/JsonConvert.java
b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/impl/JsonConvert.java
new file mode 100644
index 0000000..6918aa9
--- /dev/null
+++
b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/impl/JsonConvert.java
@@ -0,0 +1,167 @@
+/*
+ * 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.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager.impl;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.security.Principal;
+import java.util.Collection;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.security.Privilege;
+import javax.json.Json;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObjectBuilder;
+
+import org.apache.sling.jcr.jackrabbit.accessmanager.LocalPrivilege;
+import org.apache.sling.jcr.jackrabbit.accessmanager.LocalRestriction;
+
+/**
+ * Utilities to help convert ACL/ACE data to JSON
+ */
+public class JsonConvert {
+ public static final String KEY_PRINCIPAL = "principal";
+ public static final String KEY_ORDER = "order";
+ public static final String KEY_PRIVILEGES = "privileges";
+ public static final String KEY_ALLOW = "allow";
+ public static final String KEY_DENY = "deny";
+
+ private JsonConvert() {
+ // no-op
+ }
+
+ public static JsonObjectBuilder convertToJson(Principal principal,
Map<Privilege, LocalPrivilege> entry,
+ int order) {
+ JsonObjectBuilder principalObj = Json.createObjectBuilder();
+ principalObj.add(JsonConvert.KEY_PRINCIPAL, principal.getName());
+ if (order != -1) {
+ principalObj.add(JsonConvert.KEY_ORDER, order);
+ }
+ Collection<LocalPrivilege> privileges = entry.values();
+ if (!privileges.isEmpty()) {
+ JsonObjectBuilder privilegesObj = Json.createObjectBuilder();
+ for (LocalPrivilege pi : privileges) {
+ if (pi.isNone()) {
+ continue;
+ }
+ JsonObjectBuilder privilegeObj = Json.createObjectBuilder();
+
+ if (pi.isAllow()) {
+ JsonConvert.addRestrictions(privilegeObj,
JsonConvert.KEY_ALLOW, pi.getAllowRestrictions());
+ }
+ if (pi.isDeny()) {
+ JsonConvert.addRestrictions(privilegeObj,
JsonConvert.KEY_DENY, pi.getDenyRestrictions());
+ }
+ privilegesObj.add(pi.getName(), privilegeObj);
+ }
+ principalObj.add(JsonConvert.KEY_PRIVILEGES, privilegesObj);
+ }
+ return principalObj;
+ }
+
+ public static void addRestrictions(JsonObjectBuilder privilegeObj, String
key, Set<LocalRestriction> restrictions) {
+ if (restrictions.isEmpty()) {
+ privilegeObj.add(key, true);
+ } else {
+ JsonObjectBuilder allowObj = Json.createObjectBuilder();
+ for (LocalRestriction ri : restrictions) {
+ if (ri.isMultiValue()) {
+ JsonArrayBuilder rvalues = Json.createArrayBuilder();
+ for (Value value: ri.getValues()) {
+ addTo(rvalues, value);
+ }
+ allowObj.add(ri.getName(), rvalues);
+ } else {
+ addTo(allowObj, ri.getName(), ri.getValue());
+ }
+ }
+ privilegeObj.add(key, allowObj);
+ }
+ }
+
+ public static JsonObjectBuilder addTo(JsonObjectBuilder builder, String
key, Object value) {
+ value = convertJcrValue(value);
+ if (value instanceof Byte || value instanceof Short || value
instanceof Integer || value instanceof Long) {
+ builder.add(key, ((Number) value).longValue());
+ } else if (value instanceof BigDecimal) {
+ builder.add(key, (BigDecimal) value);
+ } else if (value instanceof BigInteger) {
+ builder.add(key, (BigInteger) value);
+ } else if (value instanceof Boolean) {
+ builder.add(key, (Boolean) value);
+ } else if (value instanceof Float || value instanceof Double) {
+ builder.add(key, ((Number) value).doubleValue());
+ } else if (value instanceof Privilege) {
+ JsonObjectBuilder privilegeBuilder = Json.createObjectBuilder();
+ privilegeBuilder.add("name", ((Privilege) value).getName());
+ builder.add(key, privilegeBuilder);
+ } else if (value instanceof String) {
+ builder.add(key, (String) value);
+ } else {
+ builder.add(key, value.toString());
+ }
+ return builder;
+ }
+
+ public static JsonArrayBuilder addTo(JsonArrayBuilder builder, Object
value) {
+ value = convertJcrValue(value);
+ if (value instanceof Byte || value instanceof Short || value
instanceof Integer || value instanceof Long) {
+ builder.add(((Number) value).longValue());
+ } else if (value instanceof BigDecimal) {
+ builder.add((BigDecimal) value);
+ } else if (value instanceof BigInteger) {
+ builder.add((BigInteger) value);
+ } else if (value instanceof Boolean) {
+ builder.add((Boolean) value);
+ } else if (value instanceof Float || value instanceof Double) {
+ builder.add(((Number) value).doubleValue());
+ } else if (value instanceof String) {
+ builder.add((String) value);
+ } else {
+ builder.add(value.toString());
+ }
+ return builder;
+ }
+
+ private static Object convertJcrValue(Object value) {
+ if (value instanceof Value) {
+ try {
+ Value jcrValue = (Value)value;
+ int valueType = jcrValue.getType();
+ if (valueType == PropertyType.DOUBLE) {
+ value = jcrValue.getDouble();
+ } else if (valueType == PropertyType.DECIMAL) {
+ value = jcrValue.getDecimal();
+ } else if (valueType == PropertyType.LONG) {
+ value = jcrValue.getLong();
+ } else if (valueType == PropertyType.BOOLEAN) {
+ value = jcrValue.getBoolean();
+ } else {
+ value = jcrValue.getString();
+ }
+ } catch (RepositoryException re) {
+ // should never get here
+ }
+ }
+ return value;
+ }
+
+}
diff --git
a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractAccessGetServlet.java
b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractAccessGetServlet.java
new file mode 100644
index 0000000..04968bf
--- /dev/null
+++
b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractAccessGetServlet.java
@@ -0,0 +1,187 @@
+/*
+ * 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.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager.post;
+
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.Privilege;
+import javax.json.Json;
+import javax.json.JsonObject;
+import javax.json.stream.JsonGenerator;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import
org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionDefinition;
+import
org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.resource.ResourceNotFoundException;
+import org.apache.sling.api.servlets.SlingAllMethodsServlet;
+import org.apache.sling.jcr.base.util.AccessControlUtil;
+import org.apache.sling.jcr.jackrabbit.accessmanager.LocalPrivilege;
+import org.apache.sling.jcr.jackrabbit.accessmanager.LocalRestriction;
+import org.apache.sling.jcr.jackrabbit.accessmanager.impl.PrivilegesHelper;
+import org.jetbrains.annotations.NotNull;
+
+@SuppressWarnings("serial")
+public abstract class AbstractAccessGetServlet extends SlingAllMethodsServlet {
+
+ private transient RestrictionProvider restrictionProvider;
+
+ // @Reference
+ protected void bindRestrictionProvider(RestrictionProvider rp) {
+ this.restrictionProvider = rp;
+ }
+
+ /**
+ * Return the RestrictionProvider service
+ */
+ protected RestrictionProvider getRestrictionProvider() {
+ return restrictionProvider;
+ }
+
+ /* (non-Javadoc)
+ * @see
org.apache.sling.api.servlets.SlingSafeMethodsServlet#doGet(org.apache.sling.api.SlingHttpServletRequest,
org.apache.sling.api.SlingHttpServletResponse)
+ */
+ @Override
+ protected void doGet(SlingHttpServletRequest request,
+ SlingHttpServletResponse response) throws ServletException,
+ IOException {
+
+ try {
+ Session session =
request.getResourceResolver().adaptTo(Session.class);
+ String resourcePath = request.getResource().getPath();
+ String principalId = request.getParameter("pid");
+
+ JsonObject jsonObj = internalJson(session, resourcePath,
principalId);
+ response.setContentType("application/json");
+ response.setCharacterEncoding(StandardCharsets.UTF_8.name());
+
+ boolean isTidy = false;
+ final String[] selectors =
request.getRequestPathInfo().getSelectors();
+ if (selectors.length > 0) {
+ for (final String level : selectors) {
+ if("tidy".equals(level)) {
+ isTidy = true;
+ break;
+ }
+ }
+ }
+
+ Map<String, Object> options = new HashMap<>();
+ options.put(JsonGenerator.PRETTY_PRINTING, isTidy);
+ try (JsonGenerator generator =
Json.createGeneratorFactory(options).createGenerator(response.getWriter())) {
+ generator.write(jsonObj).flush();
+ }
+ } catch (AccessDeniedException ade) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ } catch (ResourceNotFoundException rnfe) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND,
rnfe.getMessage());
+ } catch (Exception throwable) {
+ throw new ServletException(String.format("Exception while handling
GET %s with %s",
+ request.getResource().getPath(),
getClass().getName()),
+ throwable);
+ }
+ }
+
+ protected abstract JsonObject internalJson(Session session, String
resourcePath, String principalId) throws RepositoryException;
+
+ /**
+ * Verify that the user supplied arguments are valid
+ *
+ * @param jcrSession the JCR session
+ * @param resourcePath the resource path
+ * @param principalId the principal id
+ * @return the principal for the requested principalId
+ */
+ protected @NotNull Principal validateArgs(Session jcrSession, String
resourcePath, String principalId) throws RepositoryException {
+ validateArgs(jcrSession, resourcePath);
+
+ if (principalId == null) {
+ throw new RepositoryException("principalId was not submitted.");
+ }
+
+ // validate that the submitted name is valid
+ PrincipalManager principalManager =
AccessControlUtil.getPrincipalManager(jcrSession);
+ Principal principal = principalManager.getPrincipal(principalId);
+ if (principal == null) {
+ throw new RepositoryException("Invalid principalId was
submitted.");
+ }
+
+ return principal;
+ }
+
+ /**
+ * Verify that the user supplied arguments are valid
+ *
+ * @param jcrSession the JCR session
+ * @param resourcePath the resource path
+ * @param principalId the principal id
+ * @return the principal for the requested principalId
+ */
+ protected @NotNull void validateArgs(Session jcrSession, String
resourcePath) throws RepositoryException {
+ if (jcrSession == null) {
+ throw new RepositoryException("JCR Session not found");
+ }
+
+ if (resourcePath == null) {
+ throw new ResourceNotFoundException("Resource path was not
supplied.");
+ }
+
+ if (!jcrSession.nodeExists(resourcePath)) {
+ throw new ResourceNotFoundException("Resource is not a JCR Node");
+ }
+ }
+
+ protected void processACE(Map<String, RestrictionDefinition> srMap,
+ JackrabbitAccessControlEntry jrAccessControlEntry, Privilege[]
privileges,
+ Map<Privilege, LocalPrivilege> map) throws RepositoryException {
+ boolean isAllow = jrAccessControlEntry.isAllow();
+ // populate the declared restrictions
+ @NotNull
+ String[] restrictionNames = jrAccessControlEntry.getRestrictionNames();
+ Set<LocalRestriction> restrictionItems = new HashSet<>();
+ for (String restrictionName : restrictionNames) {
+ RestrictionDefinition rd = srMap.get(restrictionName);
+ boolean isMulti = rd.getRequiredType().isArray();
+ if (isMulti) {
+ restrictionItems.add(new LocalRestriction(rd,
jrAccessControlEntry.getRestrictions(restrictionName)));
+ } else {
+ restrictionItems.add(new LocalRestriction(rd,
jrAccessControlEntry.getRestriction(restrictionName)));
+ }
+ }
+
+ if (isAllow) {
+ PrivilegesHelper.allow(map, restrictionItems,
Arrays.asList(privileges));
+ } else {
+ PrivilegesHelper.deny(map, restrictionItems,
Arrays.asList(privileges));
+ }
+ }
+
+}
diff --git
a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractGetAceServlet.java
b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractGetAceServlet.java
new file mode 100644
index 0000000..46a5ddf
--- /dev/null
+++
b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractGetAceServlet.java
@@ -0,0 +1,89 @@
+/*
+ * 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.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager.post;
+
+import java.security.Principal;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.Privilege;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
+import
org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionDefinition;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.apache.sling.api.resource.ResourceNotFoundException;
+import org.apache.sling.jcr.base.util.AccessControlUtil;
+import org.apache.sling.jcr.jackrabbit.accessmanager.LocalPrivilege;
+import org.apache.sling.jcr.jackrabbit.accessmanager.impl.JsonConvert;
+import org.apache.sling.jcr.jackrabbit.accessmanager.impl.PrivilegesHelper;
+
+@SuppressWarnings("serial")
+public abstract class AbstractGetAceServlet extends AbstractAccessGetServlet {
+
+ @Override
+ protected JsonObject internalJson(Session session, String resourcePath,
String principalId) throws RepositoryException {
+ return internalGetAce(session, resourcePath, principalId);
+ }
+
+ protected JsonObject internalGetAce(Session jcrSession, String
resourcePath, String principalId) throws RepositoryException {
+ Principal principal = validateArgs(jcrSession, resourcePath,
principalId);
+
+ AccessControlEntry[] accessControlEntries =
getAccessControlEntries(jcrSession, resourcePath, principal);
+ if (accessControlEntries == null || accessControlEntries.length == 0) {
+ throw new ResourceNotFoundException(resourcePath, "No access
control entries were found");
+ }
+
+ //make a temp map for quick lookup below
+ Set<RestrictionDefinition> supportedRestrictions =
getRestrictionProvider().getSupportedRestrictions(resourcePath);
+ Map<String, RestrictionDefinition> srMap = new HashMap<>();
+ for (RestrictionDefinition restrictionDefinition :
supportedRestrictions) {
+ srMap.put(restrictionDefinition.getName(), restrictionDefinition);
+ }
+
+ Map<Privilege, LocalPrivilege> privilegeToLocalPrivilegesMap = new
HashMap<>();
+ //evaluate these in reverse order so the entries with highest
specificity are processed last
+ for (int i = accessControlEntries.length - 1; i >= 0; i--) {
+ AccessControlEntry accessControlEntry = accessControlEntries[i];
+ if (accessControlEntry instanceof JackrabbitAccessControlEntry) {
+ JackrabbitAccessControlEntry jrAccessControlEntry =
(JackrabbitAccessControlEntry)accessControlEntry;
+ Privilege[] privileges = jrAccessControlEntry.getPrivileges();
+ if (privileges != null) {
+ processACE(srMap, jrAccessControlEntry, privileges,
privilegeToLocalPrivilegesMap);
+ }
+ }
+ }
+
+ // combine any aggregates that are still valid
+ AccessControlManager acm =
AccessControlUtil.getAccessControlManager(jcrSession);
+ Map<Privilege, Integer> privilegeLongestDepthMap =
PrivilegesHelper.buildPrivilegeLongestDepthMap(acm.privilegeFromName(PrivilegeConstants.JCR_ALL));
+ PrivilegesHelper.consolidateAggregates(acm, resourcePath,
privilegeToLocalPrivilegesMap, privilegeLongestDepthMap);
+
+ // convert the data to JSON
+ JsonObjectBuilder jsonObj = JsonConvert.convertToJson(principal,
privilegeToLocalPrivilegesMap, -1);
+ return jsonObj.build();
+ }
+
+ protected abstract AccessControlEntry[] getAccessControlEntries(Session
session, String absPath, Principal principal) throws RepositoryException;
+
+}
diff --git
a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractGetAclServlet.java
b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractGetAclServlet.java
index 9b56f91..0328d45 100644
---
a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractGetAclServlet.java
+++
b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractGetAclServlet.java
@@ -16,25 +16,17 @@
*/
package org.apache.sling.jcr.jackrabbit.accessmanager.post;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
import java.security.Principal;
import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
-import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
-import javax.jcr.AccessDeniedException;
-import javax.jcr.Item;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
-import javax.jcr.Value;
import javax.jcr.security.AccessControlEntry;
import javax.jcr.security.AccessControlManager;
import javax.jcr.security.Privilege;
@@ -42,112 +34,43 @@ import javax.json.Json;
import javax.json.JsonArrayBuilder;
import javax.json.JsonObject;
import javax.json.JsonObjectBuilder;
-import javax.json.stream.JsonGenerator;
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServletResponse;
import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
import
org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionDefinition;
-import
org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
-import org.apache.sling.api.SlingHttpServletRequest;
-import org.apache.sling.api.SlingHttpServletResponse;
-import org.apache.sling.api.resource.ResourceNotFoundException;
-import org.apache.sling.api.servlets.SlingAllMethodsServlet;
import org.apache.sling.jcr.base.util.AccessControlUtil;
import org.apache.sling.jcr.jackrabbit.accessmanager.LocalPrivilege;
import org.apache.sling.jcr.jackrabbit.accessmanager.LocalRestriction;
+import org.apache.sling.jcr.jackrabbit.accessmanager.impl.JsonConvert;
import org.apache.sling.jcr.jackrabbit.accessmanager.impl.PrivilegesHelper;
-import org.jetbrains.annotations.NotNull;
@SuppressWarnings("serial")
-public abstract class AbstractGetAclServlet extends SlingAllMethodsServlet {
+public abstract class AbstractGetAclServlet extends AbstractAccessGetServlet {
- protected static final String KEY_PRINCIPAL = "principal";
- protected static final String KEY_ORDER = "order";
- protected static final String KEY_PRIVILEGES = "privileges";
- protected static final String KEY_ALLOW = "allow";
- protected static final String KEY_DENY = "deny";
/**
- * @deprecated since 3.0.12, To be removed before the exported package
version goes to 4.0
+ * @deprecated since 3.0.12, To be removed when the exported package
version goes to 4.0
+ * use {@link JsonConvert#KEY_ORDER} instead
*/
@Deprecated
- protected static final String KEY_DENIED = "denied";
+ protected static final String KEY_ORDER = JsonConvert.KEY_ORDER;
/**
- * @deprecated since 3.0.12, To be removed before the exported package
version goes to 4.0
+ * @deprecated since 3.0.12, To be removed when the exported package
version goes to 4.0
*/
@Deprecated
- protected static final String KEY_GRANTED = "granted";
-
- private transient RestrictionProvider restrictionProvider;
-
- // @Reference
- protected void bindRestrictionProvider(RestrictionProvider rp) {
- this.restrictionProvider = rp;
- }
-
+ protected static final String KEY_DENIED = "denied";
/**
- * Return the RestrictionProvider service
+ * @deprecated since 3.0.12, To be removed when the exported package
version goes to 4.0
*/
- protected RestrictionProvider getRestrictionProvider() {
- return restrictionProvider;
- }
+ @Deprecated
+ protected static final String KEY_GRANTED = "granted";
- /* (non-Javadoc)
- * @see
org.apache.sling.api.servlets.SlingSafeMethodsServlet#doGet(org.apache.sling.api.SlingHttpServletRequest,
org.apache.sling.api.SlingHttpServletResponse)
- */
@Override
- protected void doGet(SlingHttpServletRequest request,
- SlingHttpServletResponse response) throws ServletException,
- IOException {
-
- try {
- Session session =
request.getResourceResolver().adaptTo(Session.class);
- String resourcePath = request.getResource().getPath();
-
- JsonObject acl = internalGetAcl(session, resourcePath);
- response.setContentType("application/json");
- response.setCharacterEncoding(StandardCharsets.UTF_8.name());
-
- boolean isTidy = false;
- final String[] selectors =
request.getRequestPathInfo().getSelectors();
- if (selectors.length > 0) {
- for (final String level : selectors) {
- if("tidy".equals(level)) {
- isTidy = true;
- break;
- }
- }
- }
-
- Map<String, Object> options = new HashMap<>();
- options.put(JsonGenerator.PRETTY_PRINTING, isTidy);
- try (JsonGenerator generator =
Json.createGeneratorFactory(options).createGenerator(response.getWriter())) {
- generator.write(acl).flush();
- }
- } catch (AccessDeniedException ade) {
- response.sendError(HttpServletResponse.SC_NOT_FOUND);
- } catch (ResourceNotFoundException rnfe) {
- response.sendError(HttpServletResponse.SC_NOT_FOUND,
rnfe.getMessage());
- } catch (Exception throwable) {
- throw new ServletException(String.format("Exception while handling
GET %s with %s",
- request.getResource().getPath(),
getClass().getName()),
- throwable);
- }
+ protected JsonObject internalJson(Session session, String resourcePath,
String principalId) throws RepositoryException {
+ return internalGetAcl(session, resourcePath);
}
protected JsonObject internalGetAcl(Session jcrSession, String
resourcePath) throws RepositoryException {
-
- if (jcrSession == null) {
- throw new RepositoryException("JCR Session not found");
- }
-
- Item item = jcrSession.getItem(resourcePath);
- if (item != null) {
- resourcePath = item.getPath();
- } else {
- throw new ResourceNotFoundException("Resource is not a JCR Node");
- }
+ validateArgs(jcrSession, resourcePath);
//make a temp map for quick lookup below
Set<RestrictionDefinition> supportedRestrictions =
getRestrictionProvider().getSupportedRestrictions(resourcePath);
@@ -166,29 +89,11 @@ public abstract class AbstractGetAclServlet extends
SlingAllMethodsServlet {
JackrabbitAccessControlEntry jrAccessControlEntry =
(JackrabbitAccessControlEntry)accessControlEntry;
Privilege[] privileges = jrAccessControlEntry.getPrivileges();
if (privileges != null) {
- boolean isAllow = jrAccessControlEntry.isAllow();
Principal principal = accessControlEntry.getPrincipal();
principalToOrderMap.put(principal, i);
Map<Privilege, LocalPrivilege> map =
principalToPrivilegesMap.computeIfAbsent(principal, k -> new HashMap<>());
- // populate the declared restrictions
- @NotNull
- String[] restrictionNames =
jrAccessControlEntry.getRestrictionNames();
- Set<LocalRestriction> restrictionItems = new HashSet<>();
- for (String restrictionName : restrictionNames) {
- RestrictionDefinition rd = srMap.get(restrictionName);
- boolean isMulti = rd.getRequiredType().isArray();
- if (isMulti) {
- restrictionItems.add(new LocalRestriction(rd,
jrAccessControlEntry.getRestrictions(restrictionName)));
- } else {
- restrictionItems.add(new LocalRestriction(rd,
jrAccessControlEntry.getRestriction(restrictionName)));
- }
- }
- if (isAllow) {
- PrivilegesHelper.allow(map, restrictionItems,
Arrays.asList(privileges));
- } else {
- PrivilegesHelper.deny(map, restrictionItems,
Arrays.asList(privileges));
- }
+ processACE(srMap, jrAccessControlEntry, privileges, map);
}
}
}
@@ -211,85 +116,39 @@ public abstract class AbstractGetAclServlet extends
SlingAllMethodsServlet {
return jsonObj.build();
}
-
protected JsonObjectBuilder convertToJson(List<Entry<Principal,
Map<Privilege, LocalPrivilege>>> entrySetList) {
JsonObjectBuilder jsonObj = Json.createObjectBuilder();
for (int i = 0; i < entrySetList.size(); i++) {
Entry<Principal, Map<Privilege, LocalPrivilege>> entry =
entrySetList.get(i);
Principal principal = entry.getKey();
- JsonObjectBuilder principalObj = Json.createObjectBuilder();
- principalObj.add(KEY_PRINCIPAL, principal.getName());
- principalObj.add(KEY_ORDER, i);
- JsonObjectBuilder privilegesObj = Json.createObjectBuilder();
- Collection<LocalPrivilege> privileges = entry.getValue().values();
- for (LocalPrivilege pi : privileges) {
- if (pi.isNone()) {
- continue;
- }
- JsonObjectBuilder privilegeObj = Json.createObjectBuilder();
-
- if (pi.isAllow()) {
- addRestrictions(privilegeObj, KEY_ALLOW,
pi.getAllowRestrictions());
- }
- if (pi.isDeny()) {
- addRestrictions(privilegeObj, KEY_DENY,
pi.getDenyRestrictions());
- }
- privilegesObj.add(pi.getName(), privilegeObj);
- }
- principalObj.add(KEY_PRIVILEGES, privilegesObj);
+ JsonObjectBuilder principalObj =
JsonConvert.convertToJson(entry.getKey(), entry.getValue(), i);
jsonObj.add(principal.getName(), principalObj);
}
return jsonObj;
}
+ /**
+ * @deprecated use {@link JsonConvert#addRestrictions(JsonObjectBuilder,
String, Set)} instead
+ */
+ @Deprecated
protected void addRestrictions(JsonObjectBuilder privilegeObj, String key,
Set<LocalRestriction> restrictions) {
- if (restrictions.isEmpty()) {
- privilegeObj.add(key, true);
- } else {
- JsonObjectBuilder allowObj = Json.createObjectBuilder();
- for (LocalRestriction ri : restrictions) {
- if (ri.isMultiValue()) {
- JsonArrayBuilder rvalues = Json.createArrayBuilder();
- for (Value value: ri.getValues()) {
- addTo(rvalues, value);
- }
- allowObj.add(ri.getName(), rvalues);
- } else {
- addTo(allowObj, ri.getName(), ri.getValue());
- }
- }
- privilegeObj.add(key, allowObj);
- }
+ JsonConvert.addRestrictions(privilegeObj, key, restrictions);
}
+ /**
+ * @deprecated use {@link JsonConvert#addTo(javax.json.JsonArrayBuilder,
Object)} instead
+ */
+ @Deprecated
protected JsonObjectBuilder addTo(JsonObjectBuilder builder, String key,
Object value) {
- if (value instanceof Byte || value instanceof Short || value
instanceof Integer || value instanceof Long) {
- builder.add(key, ((Number) value).longValue());
- } else if (value instanceof Float || value instanceof Double) {
- builder.add(key, ((Number) value).doubleValue());
- } else if (value instanceof Privilege) {
- JsonObjectBuilder privilegeBuilder = Json.createObjectBuilder();
- privilegeBuilder.add("name", ((Privilege) value).getName());
- builder.add(key, privilegeBuilder);
- } else if (value instanceof String) {
- builder.add(key, (String) value);
- } else {
- builder.add(key, value.toString());
- }
- return builder;
+ return JsonConvert.addTo(builder, key, value);
}
+ /**
+ * @deprecated use {@link JsonConvert#addTo(JsonObjectBuilder, String,
Object)} instead
+ */
+ @Deprecated
protected JsonArrayBuilder addTo(JsonArrayBuilder builder, Object value) {
- if (value instanceof Byte || value instanceof Short || value
instanceof Integer || value instanceof Long) {
- builder.add(((Number) value).longValue());
- } else if (value instanceof Float || value instanceof Double) {
- builder.add(((Number) value).doubleValue());
- } else if (value instanceof String) {
- builder.add((String) value);
- } else {
- builder.add(value.toString());
- }
- return builder;
+ return JsonConvert.addTo(builder, value);
}
protected abstract AccessControlEntry[] getAccessControlEntries(Session
session, String absPath) throws RepositoryException;
diff --git
a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/GetAceServlet.java
b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/GetAceServlet.java
new file mode 100644
index 0000000..82e71de
--- /dev/null
+++
b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/GetAceServlet.java
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager.post;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.json.JsonObject;
+import javax.servlet.Servlet;
+
+import
org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
+import org.apache.sling.jcr.base.util.AccessControlUtil;
+import org.apache.sling.jcr.jackrabbit.accessmanager.GetAce;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+/**
+ * <p>
+ * Sling Get Servlet implementation for getting the ACE for a principal on a
JCR
+ * resource.
+ * </p>
+ * <h2>Rest Service Description</h2>
+ * <p>
+ * Get a principal's ACE for the node identified as a resource by the request
+ * URL >resource<.ace.json?pid=[principal_id]
+ * </p>
+ * <h3>Transport Details:</h3>
+ * <h4>Methods</h4>
+ * <ul>
+ * <li>GET</li>
+ * </ul>
+ * <h4>Get Parameters</h4>
+ * <dl>
+ * <dt>pid</dt>
+ * <dd>The principal id of the ACE to get in the ACL specified by the
path.</dd>
+ * </dl>
+ *
+ * <h4>Response</h4>
+ * <dl>
+ * <dt>200</dt>
+ * <dd>Success.</dd>
+ * <dt>404</dt>
+ * <dd>The resource was not found or no access control entries exist for the
principal.</dd>
+ * <dt>500</dt>
+ * <dd>Failure. JSON explains the failure.</dd>
+ * </dl>
+ */
+@Component(service = {Servlet.class, GetAce.class},
+property= {
+ "sling.servlet.resourceTypes=sling/servlet/default",
+ "sling.servlet.methods=GET",
+ "sling.servlet.selectors=ace",
+ "sling.servlet.selectors=tidy.ace",
+ "sling.servlet.extensions=json",
+ "sling.servlet.prefix:Integer=-1"
+},
+reference = {
+ @Reference(name="RestrictionProvider",
+ bind = "bindRestrictionProvider",
+ service = RestrictionProvider.class)
+}
+)
+public class GetAceServlet extends AbstractGetAceServlet implements GetAce {
+ private static final long serialVersionUID = 1654062732084983394L;
+
+ @Override
+ public JsonObject getAce(Session jcrSession, String resourcePath, String
principalId)
+ throws RepositoryException {
+ return internalGetAce(jcrSession, resourcePath, principalId);
+ }
+
+ @Override
+ protected AccessControlEntry[] getAccessControlEntries(Session session,
String absPath, Principal principal) throws RepositoryException {
+ AccessControlManager acMgr =
AccessControlUtil.getAccessControlManager(session);
+ AccessControlPolicy[] policies = acMgr.getPolicies(absPath);
+ List<AccessControlEntry> allEntries = new ArrayList<>();
+ for (AccessControlPolicy accessControlPolicy : policies) {
+ if (accessControlPolicy instanceof AccessControlList) {
+ AccessControlEntry[] accessControlEntries =
((AccessControlList)accessControlPolicy).getAccessControlEntries();
+ Stream.of(accessControlEntries)
+ .filter(entry -> principal.equals(entry.getPrincipal()))
+ .forEach(allEntries::add);
+ }
+ }
+ return allEntries.toArray(new AccessControlEntry[allEntries.size()]);
+ }
+
+}
diff --git
a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/GetEffectiveAceServlet.java
b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/GetEffectiveAceServlet.java
new file mode 100644
index 0000000..5d89d63
--- /dev/null
+++
b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/GetEffectiveAceServlet.java
@@ -0,0 +1,112 @@
+/*
+ * 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.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager.post;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Stream;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.json.JsonObject;
+import javax.servlet.Servlet;
+
+import
org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
+import org.apache.sling.jcr.base.util.AccessControlUtil;
+import org.apache.sling.jcr.jackrabbit.accessmanager.GetEffectiveAce;
+import org.osgi.service.component.annotations.Component;
+import org.osgi.service.component.annotations.Reference;
+
+/**
+ * <p>
+ * Sling Get Servlet implementation for getting the effective ACE for a
principal on a JCR
+ * resource.
+ * </p>
+ * <h2>Rest Service Description</h2>
+ * <p>
+ * Get a principal's ACE for the node identified as a resource by the request
+ * URL >resource<.eace.json?pid=[principal_id]
+ * </p>
+ * <h3>Transport Details:</h3>
+ * <h4>Methods</h4>
+ * <ul>
+ * <li>GET</li>
+ * </ul>
+ * <h4>Get Parameters</h4>
+ * <dl>
+ * <dt>pid</dt>
+ * <dd>The principal id of the ACE to get in the effective ACL specified by
the path.</dd>
+ * </dl>
+ *
+ * <h4>Response</h4>
+ * <dl>
+ * <dt>200</dt>
+ * <dd>Success.</dd>
+ * <dt>404</dt>
+ * <dd>The resource was not found or no access control entries exist for the
principal.</dd>
+ * <dt>500</dt>
+ * <dd>Failure. JSON explains the failure.</dd>
+ * </dl>
+ */
+@Component(service = {Servlet.class, GetEffectiveAce.class},
+property= {
+ "sling.servlet.resourceTypes=sling/servlet/default",
+ "sling.servlet.methods=GET",
+ "sling.servlet.selectors=eace",
+ "sling.servlet.selectors=tidy.eace",
+ "sling.servlet.extensions=json",
+ "sling.servlet.prefix:Integer=-1"
+},
+reference = {
+ @Reference(name="RestrictionProvider",
+ bind = "bindRestrictionProvider",
+ service = RestrictionProvider.class)
+}
+)
+public class GetEffectiveAceServlet extends AbstractGetAceServlet implements
GetEffectiveAce {
+ private static final long serialVersionUID = 1654062732084983394L;
+
+ @Override
+ public JsonObject getEffectiveAce(Session jcrSession, String resourcePath,
String principalId)
+ throws RepositoryException {
+ return internalGetAce(jcrSession, resourcePath, principalId);
+ }
+
+ @Override
+ protected AccessControlEntry[] getAccessControlEntries(Session session,
String absPath, Principal principal) throws RepositoryException {
+ AccessControlManager acMgr =
AccessControlUtil.getAccessControlManager(session);
+ AccessControlPolicy[] policies = acMgr.getEffectivePolicies(absPath);
+ List<AccessControlEntry> allEntries = new ArrayList<>();
+ for (AccessControlPolicy policy : policies) {
+ if (policy instanceof AccessControlList) {
+ AccessControlEntry[] accessControlEntries =
((AccessControlList)policy).getAccessControlEntries();
+ Stream.of(accessControlEntries)
+ .filter(entry -> principal.equals(entry.getPrincipal()))
+ .forEach(allEntries::add);
+ }
+ }
+ return allEntries.toArray(new AccessControlEntry[allEntries.size()]);
+ }
+
+}
diff --git
a/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/impl/JsonConvertTest.java
b/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/impl/JsonConvertTest.java
new file mode 100644
index 0000000..1ad476f
--- /dev/null
+++
b/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/impl/JsonConvertTest.java
@@ -0,0 +1,309 @@
+/*
+ * 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.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager.impl;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.math.BigDecimal;
+import java.math.BigInteger;
+import java.security.Principal;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.Privilege;
+import javax.json.Json;
+import javax.json.JsonArray;
+import javax.json.JsonArrayBuilder;
+import javax.json.JsonObject;
+import javax.json.JsonObjectBuilder;
+import javax.json.JsonString;
+import javax.json.JsonValue;
+
+import
org.apache.jackrabbit.oak.security.authorization.restriction.RestrictionProviderImpl;
+import
org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
+import
org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionDefinition;
+import
org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
+import org.apache.jackrabbit.oak.spi.security.principal.PrincipalImpl;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.apache.jackrabbit.value.ValueFactoryImpl;
+import org.apache.sling.jcr.base.util.AccessControlUtil;
+import org.apache.sling.jcr.jackrabbit.accessmanager.LocalPrivilege;
+import org.apache.sling.jcr.jackrabbit.accessmanager.LocalRestriction;
+import org.apache.sling.testing.mock.sling.ResourceResolverType;
+import org.apache.sling.testing.mock.sling.junit.SlingContext;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class JsonConvertTest {
+
+ @Rule
+ public final SlingContext context = new
SlingContext(ResourceResolverType.JCR_OAK);
+
+ private AccessControlManager acm;
+
+ private Map<String, RestrictionDefinition> srMap;
+
+ @Before
+ public void buildPrivilegesMap() throws RepositoryException {
+ context.registerService(new RestrictionProviderImpl());
+ Session session = context.resourceResolver().adaptTo(Session.class);
+ acm = AccessControlUtil.getAccessControlManager(session);
+ }
+
+ private Privilege priv(String privilegeName) throws RepositoryException {
+ return acm.privilegeFromName(privilegeName);
+ }
+
+ private RestrictionDefinition rd(String restrictionName) {
+ if (srMap == null) {
+ //make a temp map for quick lookup below
+ RestrictionProvider restrictionProvider =
context.getService(RestrictionProvider.class);
+ Set<RestrictionDefinition> supportedRestrictions =
restrictionProvider.getSupportedRestrictions("/");
+ srMap = new HashMap<>();
+ for (RestrictionDefinition restrictionDefinition :
supportedRestrictions) {
+ srMap.put(restrictionDefinition.getName(),
restrictionDefinition);
+ }
+ }
+ return srMap.get(restrictionName);
+ }
+
+ private Value val(String value) {
+ return ValueFactoryImpl.getInstance().createValue(value);
+ }
+ private Value[] vals(String ... value) {
+ Value[] values = new Value[value.length];
+ ValueFactory vf = ValueFactoryImpl.getInstance();
+ for (int i = 0; i < value.length; i++) {
+ values[i] = vf.createValue(value[i]);
+ }
+ return values;
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.jackrabbit.accessmanager.impl.JsonConvert#convertToJson(java.security.Principal,
java.util.Map, int)}.
+ */
+ @Test
+ public void testConvertToJson() throws RepositoryException {
+ Principal principal = new PrincipalImpl("testuser");
+ LocalPrivilege lp1 = new
LocalPrivilege(priv(PrivilegeConstants.JCR_READ));
+ lp1.setAllow(true);
+ LocalPrivilege lp2 = new
LocalPrivilege(priv(PrivilegeConstants.JCR_WRITE));
+ lp2.setDeny(true);
+ LocalPrivilege lp3 = new
LocalPrivilege(priv(PrivilegeConstants.JCR_READ_ACCESS_CONTROL));
+ LocalPrivilege lp4 = new
LocalPrivilege(priv(PrivilegeConstants.JCR_NODE_TYPE_MANAGEMENT));
+ lp4.setAllow(true);
+ lp4.setAllowRestrictions(Collections.singleton(new
LocalRestriction(rd(AccessControlConstants.REP_GLOB), val("/hello"))));
+ LocalPrivilege lp5 = new
LocalPrivilege(priv(PrivilegeConstants.JCR_MODIFY_ACCESS_CONTROL));
+ lp5.setDeny(true);
+ lp5.setDenyRestrictions(Collections.singleton(new
LocalRestriction(rd(AccessControlConstants.REP_ITEM_NAMES), vals("item1",
"item2"))));
+ Map<Privilege, LocalPrivilege> entry = new HashMap<>();
+ entry.put(lp1.getPrivilege(), lp1);
+ entry.put(lp2.getPrivilege(), lp2);
+ entry.put(lp3.getPrivilege(), lp3);
+ entry.put(lp4.getPrivilege(), lp4);
+ entry.put(lp5.getPrivilege(), lp5);
+ int order = 1;
+ JsonObjectBuilder principalObj = JsonConvert.convertToJson(principal,
entry, order);
+ assertNotNull(principalObj);
+ JsonObject build = principalObj.build();
+ assertEquals("testuser", build.getString(JsonConvert.KEY_PRINCIPAL));
+ assertEquals(1, build.getInt(JsonConvert.KEY_ORDER));
+ JsonObject privilegesObj =
build.getJsonObject(JsonConvert.KEY_PRIVILEGES);
+ assertNotNull(privilegesObj);
+ assertEquals(4, privilegesObj.size());
+
+ JsonValue jsonValue1 = privilegesObj.get(PrivilegeConstants.JCR_READ);
+ assertTrue(jsonValue1 instanceof JsonObject);
+ assertTrue(((JsonObject)jsonValue1).getBoolean(JsonConvert.KEY_ALLOW));
+
+ JsonValue jsonValue2 = privilegesObj.get(PrivilegeConstants.JCR_WRITE);
+ assertTrue(jsonValue2 instanceof JsonObject);
+ assertTrue(((JsonObject)jsonValue2).getBoolean(JsonConvert.KEY_DENY));
+
+ JsonValue jsonValue4 =
privilegesObj.get(PrivilegeConstants.JCR_NODE_TYPE_MANAGEMENT);
+ assertTrue(jsonValue4 instanceof JsonObject);
+ JsonObject allowObj4 =
((JsonObject)jsonValue4).getJsonObject(JsonConvert.KEY_ALLOW);
+ assertNotNull(allowObj4);
+ Object globRestrictionObj4 =
allowObj4.get(AccessControlConstants.REP_GLOB);
+ assertTrue(globRestrictionObj4 instanceof JsonString);
+ assertEquals("/hello", ((JsonString)globRestrictionObj4).getString());
+
+ JsonValue jsonValue5 =
privilegesObj.get(PrivilegeConstants.JCR_MODIFY_ACCESS_CONTROL);
+ assertTrue(jsonValue5 instanceof JsonObject);
+ JsonObject allowObj5 =
((JsonObject)jsonValue5).getJsonObject(JsonConvert.KEY_DENY);
+ assertNotNull(allowObj5);
+ Object itemNamesRestrictionObj5 =
allowObj5.get(AccessControlConstants.REP_ITEM_NAMES);
+ assertTrue(itemNamesRestrictionObj5 instanceof JsonArray);
+ assertEquals("item1",
((JsonArray)itemNamesRestrictionObj5).getString(0));
+ assertEquals("item2",
((JsonArray)itemNamesRestrictionObj5).getString(1));
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.jackrabbit.accessmanager.impl.JsonConvert#addRestrictions(javax.json.JsonObjectBuilder,
java.lang.String, java.util.Set)}.
+ */
+ @Test
+ public void testAddRestrictions() {
+ JsonObjectBuilder privilegeObj = Json.createObjectBuilder();
+ String key = JsonConvert.KEY_ALLOW;
+ Set<LocalRestriction> restrictions = new HashSet<>();
+ restrictions.add(new
LocalRestriction(rd(AccessControlConstants.REP_GLOB), val("/hello")));
+ restrictions.add(new
LocalRestriction(rd(AccessControlConstants.REP_ITEM_NAMES), vals("item1",
"item2")));
+ JsonConvert.addRestrictions(privilegeObj, key, restrictions);
+ JsonObject build = privilegeObj.build();
+ assertNotNull(build);
+ JsonObject allowObj = build.getJsonObject(JsonConvert.KEY_ALLOW);
+ assertNotNull(allowObj);
+ Object globRestrictionObj =
allowObj.get(AccessControlConstants.REP_GLOB);
+ assertTrue(globRestrictionObj instanceof JsonString);
+ assertEquals("/hello", ((JsonString)globRestrictionObj).getString());
+ Object itemNamesRestrictionObj =
allowObj.get(AccessControlConstants.REP_ITEM_NAMES);
+ assertTrue(itemNamesRestrictionObj instanceof JsonArray);
+ assertEquals("item1",
((JsonArray)itemNamesRestrictionObj).getString(0));
+ assertEquals("item2",
((JsonArray)itemNamesRestrictionObj).getString(1));
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.jackrabbit.accessmanager.impl.JsonConvert#addTo(javax.json.JsonObjectBuilder,
java.lang.String, java.lang.Object)}.
+ */
+ @Test
+ public void testAddToJsonObjectBuilderStringObject() throws
RepositoryException {
+ JsonObjectBuilder builder = Json.createObjectBuilder();
+
+ String key = JsonConvert.KEY_ALLOW;
+ Function<JsonObject, Object> doubleFn = json ->
json.getJsonNumber(key).doubleValue();
+ Function<JsonObject, Object> bigDecimalFn = json ->
json.getJsonNumber(key).bigDecimalValue();
+ Function<JsonObject, Object> bigIntegerFn = json ->
json.getJsonNumber(key).bigIntegerValue();
+ Function<JsonObject, Object> longFn = json ->
json.getJsonNumber(key).longValue();
+ Function<JsonObject, Object> intFn = json ->
json.getJsonNumber(key).intValue();
+ Function<JsonObject, Object> booleanFn = json -> json.getBoolean(key);
+ Function<JsonObject, Object> stringFn = json -> json.getString(key);
+ Function<JsonObject, Object> privFn = json ->
json.getJsonObject(key).getString("name");
+
+ ValueFactory vf = ValueFactoryImpl.getInstance();
+ // data to test [label, value, expectedValueFromJson, lookupFromJsonFn]
+ Object[][] candidates = new Object[][] {
+ // JCR Value types
+ {"JCR double Value", vf.createValue((double)1.1), 1.1, doubleFn},
+ {"JCR BigDecimal Value", vf.createValue(new BigDecimal("1.1")),
new BigDecimal("1.1"), bigDecimalFn},
+ {"JCR long Value", vf.createValue(1L), 1L, longFn},
+ {"JCR boolean Value", vf.createValue(true), true, booleanFn},
+ {"JCR string Value", vf.createValue("hello"), "hello", stringFn},
+
+ // non-JCR values
+ {"byte value", (byte)1, 1, intFn},
+ {"short value", (short)1, 1, intFn},
+ {"int value", 1, 1, intFn},
+ {"long value", 1L, 1L, longFn},
+ {"BigDecimal value", new BigDecimal("1.1"), new BigDecimal("1.1"),
bigDecimalFn},
+ {"BigInteger value", new BigInteger("1"), new BigInteger("1"),
bigIntegerFn},
+ {"true boolean value", true, true, booleanFn},
+ {"false boolean value", false, false, booleanFn},
+ {"float value", (float)1.1, (double)1.1, doubleFn},
+ {"double value", 1.1, 1.1, doubleFn},
+ {"string value", "hello", "hello", stringFn},
+ {"privilege value", priv(PrivilegeConstants.JCR_READ),
PrivilegeConstants.JCR_READ, privFn},
+ {"object value", new StringBuilder().append("hello"), "hello",
stringFn}
+ };
+ for (Object[] objects : candidates) {
+ Object value = objects[1];
+ JsonConvert.addTo(builder, key, value);
+ JsonObject build = builder.build();
+ assertNotNull(build);
+ assertEquals(1, build.size());
+ @SuppressWarnings("unchecked")
+ Function<JsonObject, Object> supplier = (Function<JsonObject,
Object>)objects[3];
+ if (objects[2] instanceof Double) {
+ double epsilon = 0.000001d;
+ assertEquals(String.format("%s was not the expected value",
objects[0]), (double)objects[2], (double)supplier.apply(build), epsilon);
+ } else {
+ assertEquals(String.format("%s was not the expected value",
objects[0]), objects[2], supplier.apply(build));
+ }
+ }
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.jackrabbit.accessmanager.impl.JsonConvert#addTo(javax.json.JsonArrayBuilder,
java.lang.Object)}.
+ */
+ @Test
+ public void testAddToJsonArrayBuilderObject() {
+ JsonArrayBuilder builder = Json.createArrayBuilder();
+
+ Function<JsonArray, Object> doubleFn = json ->
json.getJsonNumber(0).doubleValue();
+ Function<JsonArray, Object> bigDecimalFn = json ->
json.getJsonNumber(0).bigDecimalValue();
+ Function<JsonArray, Object> bigIntegerFn = json ->
json.getJsonNumber(0).bigIntegerValue();
+ Function<JsonArray, Object> longFn = json ->
json.getJsonNumber(0).longValue();
+ Function<JsonArray, Object> intFn = json ->
json.getJsonNumber(0).intValue();
+ Function<JsonArray, Object> booleanFn = json -> json.getBoolean(0);
+ Function<JsonArray, Object> stringFn = json -> json.getString(0);
+
+ ValueFactory vf = ValueFactoryImpl.getInstance();
+ // data to test [label, value, expectedValueFromJson, lookupFromJsonFn]
+ Object[][] candidates = new Object[][] {
+ // JCR Value types
+ {"JCR double Value", vf.createValue((double)1.1), 1.1, doubleFn},
+ {"JCR BigDecimal Value", vf.createValue(new BigDecimal("1.1")),
new BigDecimal("1.1"), bigDecimalFn},
+ {"JCR long Value", vf.createValue(1L), 1L, longFn},
+ {"JCR boolean Value", vf.createValue(true), true, booleanFn},
+ {"JCR string Value", vf.createValue("hello"), "hello", stringFn},
+
+ // non-JCR values
+ {"byte value", (byte)1, 1, intFn},
+ {"short value", (short)1, 1, intFn},
+ {"int value", 1, 1, intFn},
+ {"long value", 1L, 1L, longFn},
+ {"BigDecimal value", new BigDecimal("1.1"), new BigDecimal("1.1"),
bigDecimalFn},
+ {"BigInteger value", new BigInteger("1"), new BigInteger("1"),
bigIntegerFn},
+ {"true boolean value", true, true, booleanFn},
+ {"false boolean value", false, false, booleanFn},
+ {"float value", (float)1.1, (double)1.1, doubleFn},
+ {"double value", 1.1, 1.1, doubleFn},
+ {"string value", "hello", "hello", stringFn},
+ {"object value", new StringBuilder().append("hello"), "hello",
stringFn}
+ };
+ for (Object[] objects : candidates) {
+ Object value = objects[1];
+ JsonConvert.addTo(builder, value);
+ JsonArray build = builder.build();
+ assertNotNull(build);
+ assertEquals(1, build.size());
+ @SuppressWarnings("unchecked")
+ Function<JsonArray, Object> supplier = (Function<JsonArray,
Object>)objects[3];
+ if (objects[2] instanceof Double) {
+ double epsilon = 0.000001d;
+ assertEquals(String.format("%s was not the expected value",
objects[0]), (double)objects[2], (double)supplier.apply(build), epsilon);
+ } else {
+ assertEquals(String.format("%s was not the expected value",
objects[0]), objects[2], supplier.apply(build));
+ }
+ }
+ }
+
+}
diff --git
a/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/it/GetAceIT.java
b/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/it/GetAceIT.java
new file mode 100644
index 0000000..4cf608e
--- /dev/null
+++
b/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/it/GetAceIT.java
@@ -0,0 +1,138 @@
+/*
+ * 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.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager.it;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.json.JsonException;
+import javax.json.JsonObject;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.http.NameValuePair;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+
+/**
+ * Tests for the 'ace' Sling Get Operation
+ */
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class GetAceIT extends AccessManagerClientTestSupport {
+
+ protected void commonDeclaredAceForUser(String selector) throws
IOException {
+ testUserId = createTestUser();
+ testFolderUrl = createTestFolder(null, "sling-tests",
+ "{ \"jcr:primaryType\": \"nt:unstructured\", \"child\" : {
\"childPropOne\" : true } }");
+
+ //1. create an initial set of privileges
+ List<NameValuePair> postParams = new AcePostParamsBuilder(testUserId)
+ .withPrivilege(PrivilegeConstants.JCR_WRITE,
PrivilegeValues.ALLOW)
+ .build();
+ addOrUpdateAce(testFolderUrl, postParams);
+
+ Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+
+ //fetch the JSON for the ace to verify the settings.
+ String getUrl = testFolderUrl + "." + selector + ".json?pid=" +
testUserId;
+
+ String json = getAuthenticatedContent(creds, getUrl,
CONTENT_TYPE_JSON, HttpServletResponse.SC_OK);
+ assertNotNull(json);
+ JsonObject aceObject = parseJson(json);
+
+ String principalString = aceObject.getString("principal");
+ assertEquals(testUserId, principalString);
+
+ JsonObject privilegesObject = aceObject.getJsonObject("privileges");
+ assertNotNull(privilegesObject);
+ assertEquals(1, privilegesObject.size());
+ //allow privilege
+ assertPrivilege(privilegesObject, true, PrivilegeValues.ALLOW,
PrivilegeConstants.JCR_WRITE);
+ }
+
+ /**
+ * ACE servlet returns correct information
+ */
+ @Test
+ public void testDeclaredAceForUser() throws IOException, JsonException {
+ commonDeclaredAceForUser("ace");
+ }
+
+ /**
+ * ACE servlet returns correct information
+ */
+ @Test
+ public void testTidyDeclaredAceForUser() throws IOException, JsonException
{
+ commonDeclaredAceForUser("tidy.ace");
+ }
+
+ /**
+ * ACE servlet returns 404 when no declared ACE
+ */
+ @Test
+ public void testNoDeclaredAceForUser() throws IOException, JsonException {
+ testUserId = createTestUser();
+ testFolderUrl = createTestFolder(null, "sling-tests",
+ "{ \"jcr:primaryType\": \"nt:unstructured\", \"child\" : {
\"childPropOne\" : true } }");
+
+ //1. create an initial set of privileges
+ List<NameValuePair> postParams = new AcePostParamsBuilder(testUserId)
+ .withPrivilege(PrivilegeConstants.JCR_WRITE,
PrivilegeValues.ALLOW)
+ .build();
+ addOrUpdateAce(testFolderUrl, postParams);
+
+ Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+
+ //fetch the JSON for the ace to verify the settings.
+ String getUrl = testFolderUrl + "/child.ace.json?pid=" + testUserId;
+ // no declared access control entry returns a 404
+ assertAuthenticatedHttpStatus(creds, getUrl,
HttpServletResponse.SC_NOT_FOUND, "Did not expect an ace to be returned");
+ }
+
+ /**
+ * ACE servlet returns 404 when no read access rights permissions
+ */
+ @Test
+ public void testNoAccessToDeclaredAceForUser() throws IOException,
JsonException {
+ testUserId = createTestUser();
+ testFolderUrl = createTestFolder(null, "sling-tests",
+ "{ \"jcr:primaryType\": \"nt:unstructured\", \"child\" : {
\"childPropOne\" : true } }");
+
+ //1. create an initial set of privileges
+ List<NameValuePair> postParams = new AcePostParamsBuilder(testUserId)
+ .withPrivilege(PrivilegeConstants.JCR_READ_ACCESS_CONTROL,
PrivilegeValues.DENY)
+ .build();
+ addOrUpdateAce(testFolderUrl, postParams);
+
+ Credentials creds = new UsernamePasswordCredentials(testUserId,
"testPwd");
+
+ //fetch the JSON for the ace to verify the settings.
+ String getUrl = testFolderUrl + "/child.ace.json?pid=" + testUserId;
+ // no declared access control entry returns a 404
+ assertAuthenticatedHttpStatus(creds, getUrl,
HttpServletResponse.SC_NOT_FOUND, "Did not expect an ace to be returned");
+ }
+
+}
diff --git
a/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/it/GetAceServiceIT.java
b/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/it/GetAceServiceIT.java
new file mode 100644
index 0000000..3cbb1d5
--- /dev/null
+++
b/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/it/GetAceServiceIT.java
@@ -0,0 +1,225 @@
+/*
+ * 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.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager.it;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.util.Collections;
+
+import javax.inject.Inject;
+import javax.jcr.Node;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.json.JsonObject;
+
+import
org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.apache.sling.api.resource.ResourceNotFoundException;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.jcr.jackrabbit.accessmanager.GetAce;
+import org.apache.sling.jcr.jackrabbit.accessmanager.ModifyAce;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+
+/**
+ * Tests for the 'modifyAce' inproc service
+ */
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class GetAceServiceIT extends AccessManagerClientTestSupport {
+
+ @Inject
+ private ModifyAce modifyAce;
+
+ @Inject
+ private GetAce getAce;
+
+ @Inject
+ protected SlingRepository repository;
+
+ protected Session adminSession;
+
+ private Node testNode;
+
+ @Before
+ public void setup() throws RepositoryException {
+ adminSession = repository.login(new SimpleCredentials("admin",
"admin".toCharArray()));
+ assertNotNull("Expected adminSession to not be null", adminSession);
+ testNode = adminSession.getRootNode().addNode("testNode");
+ adminSession.save();
+ }
+
+ @After
+ public void teardown() throws RepositoryException {
+ adminSession.refresh(false);
+ testNode.remove();
+ if (adminSession.hasPendingChanges()) {
+ adminSession.save();
+ }
+ adminSession.logout();
+ }
+
+ protected JsonObject ace(String path, String principalId) throws
RepositoryException {
+ assertNotNull(getAce);
+ JsonObject aceObject = getAce.getAce(adminSession, path, principalId);
+ assertNotNull(aceObject);
+ return aceObject;
+ }
+
+ protected JsonObject acePrivleges(String path, String principalId) throws
RepositoryException {
+ JsonObject ace = ace(path, principalId);
+ JsonObject privilegesObject = ace.getJsonObject("privileges");
+ assertNotNull(privilegesObject);
+ return privilegesObject;
+ }
+
+ private Value val(int type, String value) throws RepositoryException {
+ return adminSession.getValueFactory().createValue(value, type);
+ }
+ private Value[] vals(int type, String ... value) throws
RepositoryException {
+ Value[] values = new Value[value.length];
+ ValueFactory vf = adminSession.getValueFactory();
+ for (int i = 0; i < value.length; i++) {
+ values[i] = vf.createValue(value[i], type);
+ }
+ return values;
+ }
+
+ @Test
+ public void testGetAceWithPrivileges() throws RepositoryException {
+ assertNotNull(modifyAce);
+ modifyAce.modifyAce(adminSession,
+ testNode.getPath(),
+ "everyone",
+ Collections.singletonMap(PrivilegeConstants.JCR_READ, "allow"),
+ "first");
+ // autosaved, so nothing should be pending
+ assertFalse(adminSession.hasPendingChanges());
+
+ JsonObject aceObject = ace(testNode.getPath(), "everyone");
+
+ JsonObject privilegesObject = aceObject.getJsonObject("privileges");
+ assertNotNull(privilegesObject);
+ assertEquals(1, privilegesObject.size());
+ //allow
+ assertPrivilege(privilegesObject, true, PrivilegeValues.ALLOW,
PrivilegeConstants.JCR_READ);
+ }
+
+ @Test
+ public void testGetAceWithRestrictions() throws RepositoryException {
+ assertNotNull(modifyAce);
+ modifyAce.modifyAce(adminSession,
+ testNode.getPath(),
+ "everyone",
+ Collections.singletonMap(PrivilegeConstants.JCR_READ, "allow"),
+ "first",
+ Collections.singletonMap(AccessControlConstants.REP_GLOB,
val(PropertyType.STRING, "/hello")),
+
Collections.singletonMap(AccessControlConstants.REP_ITEM_NAMES,
vals(PropertyType.NAME, "child1", "child2")),
+ Collections.emptySet());
+ // autosaved, so should be nothing pending
+ assertFalse(adminSession.hasPendingChanges());
+
+ JsonObject aceObject = ace(testNode.getPath(), "everyone");
+
+ JsonObject privilegesObject = aceObject.getJsonObject("privileges");
+ assertNotNull(privilegesObject);
+ assertEquals(1, privilegesObject.size());
+ //allow
+ assertPrivilege(privilegesObject, true, PrivilegeValues.ALLOW,
PrivilegeConstants.JCR_READ);
+ }
+
+ @Test
+ public void testGetAceWithNullSessionArg() throws RepositoryException {
+ assertNotNull(modifyAce);
+ String resourcePath = testNode.getPath();
+ try {
+ getAce.getAce(null,
+ resourcePath,
+ "everyone");
+ fail("Expected RepositoryException");
+ } catch (RepositoryException re) {
+ assertEquals("JCR Session not found", re.getMessage());
+ }
+ }
+
+ @Test
+ public void testGetAceWithNullResourcePathArg() throws RepositoryException
{
+ assertNotNull(modifyAce);
+ try {
+ getAce.getAce(adminSession,
+ null,
+ "everyone");
+ fail("Expected ResourceNotFoundException");
+ } catch (ResourceNotFoundException rnfe) {
+ //expected
+ }
+ }
+
+ @Test
+ public void testGetAceWithNotExistingResourcePathArg() throws
RepositoryException {
+ assertNotNull(modifyAce);
+ try {
+ getAce.getAce(adminSession,
+ "/not_a_real_path",
+ "everyone");
+ fail("Expected ResourceNotFoundException");
+ } catch (ResourceNotFoundException rnfe) {
+ //expected
+ }
+ }
+
+ @Test
+ public void testGetAceWithNullPrincipalIdArg() throws RepositoryException {
+ assertNotNull(modifyAce);
+ String resourcePath = testNode.getPath();
+ try {
+ getAce.getAce(adminSession,
+ resourcePath,
+ null);
+ fail("Expected RepositoryException");
+ } catch (RepositoryException re) {
+ assertEquals("principalId was not submitted.", re.getMessage());
+ }
+ }
+
+ @Test
+ public void testGetAceWithNotExistingPrincipalIdArg() throws
RepositoryException {
+ assertNotNull(modifyAce);
+ String resourcePath = testNode.getPath();
+ try {
+ getAce.getAce(adminSession,
+ resourcePath,
+ "not_a_real_principalid");
+ fail("Expected RepositoryException");
+ } catch (RepositoryException re) {
+ assertEquals("Invalid principalId was submitted.",
re.getMessage());
+ }
+ }
+
+}
diff --git
a/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/it/GetAclIT.java
b/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/it/GetAclIT.java
index deb2fcd..8296f79 100644
---
a/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/it/GetAclIT.java
+++
b/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/it/GetAclIT.java
@@ -371,4 +371,27 @@ public class GetAclIT extends
AccessManagerClientTestSupport {
assertEquals(1, privilegesObject.size());
assertPrivilege(privilegesObject, true, PrivilegeValues.DENY,
PrivilegeConstants.JCR_ALL);
}
+
+ /**
+ * ACL servlet returns 404 when no read access rights permissions
+ */
+ @Test
+ public void testNoAccessToDeclaredAclForUser() throws IOException,
JsonException {
+ testUserId = createTestUser();
+ testFolderUrl = createTestFolder(null, "sling-tests",
+ "{ \"jcr:primaryType\": \"nt:unstructured\", \"child\" : {
\"childPropOne\" : true } }");
+
+ //1. create an initial set of privileges
+ List<NameValuePair> postParams = new AcePostParamsBuilder(testUserId)
+ .withPrivilege(PrivilegeConstants.JCR_READ_ACCESS_CONTROL,
PrivilegeValues.DENY)
+ .build();
+ addOrUpdateAce(testFolderUrl, postParams);
+
+ Credentials creds = new UsernamePasswordCredentials(testUserId,
"testPwd");
+
+ //fetch the JSON for the ace to verify the settings.
+ String getUrl = testFolderUrl + "/child.acl.json";
+ // no declared access control entry returns a 404
+ assertAuthenticatedHttpStatus(creds, getUrl,
HttpServletResponse.SC_NOT_FOUND, "Did not expect an ace to be returned");
+ }
}
diff --git
a/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/it/GetEaceIT.java
b/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/it/GetEaceIT.java
new file mode 100644
index 0000000..b253492
--- /dev/null
+++
b/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/it/GetEaceIT.java
@@ -0,0 +1,137 @@
+/*
+ * 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.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager.it;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+
+import java.io.IOException;
+import java.util.List;
+
+import javax.json.JsonException;
+import javax.json.JsonObject;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.http.NameValuePair;
+import org.apache.http.auth.Credentials;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+
+/**
+ * Tests for the 'eace' Sling Get Operation
+ */
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class GetEaceIT extends AccessManagerClientTestSupport {
+
+ protected void commonEffectiveAceForUser(String selector) throws
IOException {
+ testUserId = createTestUser();
+ testFolderUrl = createTestFolder(null, "sling-tests1",
+ "{ \"jcr:primaryType\": \"nt:unstructured\", \"child\" : {
\"childPropOne\" : true } }");
+
+ //1. create an initial set of privileges
+ List<NameValuePair> postParams = new AcePostParamsBuilder(testUserId)
+ .withPrivilege(PrivilegeConstants.JCR_WRITE,
PrivilegeValues.ALLOW)
+ .build();
+ addOrUpdateAce(testFolderUrl, postParams);
+
+ Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+
+ //fetch the JSON for the ace to verify the settings.
+ String getUrl = testFolderUrl + "/child." + selector + ".json?pid=" +
testUserId;
+
+ String json = getAuthenticatedContent(creds, getUrl,
CONTENT_TYPE_JSON, HttpServletResponse.SC_OK);
+ assertNotNull(json);
+ JsonObject aceObject = parseJson(json);
+
+ String principalString = aceObject.getString("principal");
+ assertEquals(testUserId, principalString);
+
+ JsonObject privilegesObject = aceObject.getJsonObject("privileges");
+ assertNotNull(privilegesObject);
+ assertEquals(1, privilegesObject.size());
+ //allow privilege
+ assertPrivilege(privilegesObject, true, PrivilegeValues.ALLOW,
PrivilegeConstants.JCR_WRITE);
+ }
+
+ /**
+ * Effective ACE servlet returns correct information
+ */
+ @Test
+ public void testEffectiveAceForUser() throws IOException, JsonException {
+ commonEffectiveAceForUser("eace");
+ }
+
+ /**
+ * Effective ACE servlet returns correct information
+ */
+ @Test
+ public void testTidyEffectiveAceForUser() throws IOException,
JsonException {
+ commonEffectiveAceForUser("tidy.eace");
+ }
+
+ /**
+ * Effective ACE servlet returns correct information
+ */
+ @Test
+ public void testNoEffectiveAceForUser() throws IOException, JsonException {
+ testUserId = createTestUser();
+ testUserId2 = createTestUser();
+ testFolderUrl = createTestFolder(null, "sling-tests2",
+ "{ \"jcr:primaryType\": \"nt:unstructured\", \"child\" : {
\"childPropOne\" : true } }");
+
+ //1. create an initial set of privileges
+ List<NameValuePair> postParams = new AcePostParamsBuilder(testUserId)
+ .withPrivilege(PrivilegeConstants.JCR_WRITE,
PrivilegeValues.ALLOW)
+ .build();
+ addOrUpdateAce(testFolderUrl, postParams);
+
+ Credentials creds = new UsernamePasswordCredentials("admin", "admin");
+
+ //fetch the JSON for the ace to verify the settings.
+ String getUrl = testFolderUrl + "/child.eace.json?pid=" + testUserId2;
+ assertAuthenticatedHttpStatus(creds, getUrl,
HttpServletResponse.SC_NOT_FOUND, "Did not expect an ace to be returned");
+ }
+
+ /**
+ * Effective ACE servlet returns 404 when no read access rights permissions
+ */
+ @Test
+ public void testNoAccessToEffectiveAceForUser() throws IOException,
JsonException {
+ testUserId = createTestUser();
+ testFolderUrl = createTestFolder(null, "sling-tests2",
+ "{ \"jcr:primaryType\": \"nt:unstructured\", \"child\" : {
\"childPropOne\" : true } }");
+
+ //1. create an initial set of privileges
+ List<NameValuePair> postParams = new AcePostParamsBuilder(testUserId)
+ .withPrivilege(PrivilegeConstants.JCR_READ_ACCESS_CONTROL,
PrivilegeValues.DENY)
+ .build();
+ addOrUpdateAce(testFolderUrl, postParams);
+
+ Credentials creds = new UsernamePasswordCredentials(testUserId,
"testPwd");
+
+ //fetch the JSON for the ace to verify the settings.
+ String getUrl = testFolderUrl + ".eace.json?pid=" + testUserId;
+ assertAuthenticatedHttpStatus(creds, getUrl,
HttpServletResponse.SC_NOT_FOUND, "Did not expect an ace to be returned");
+ }
+
+}
diff --git
a/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/it/GetEaceServiceIT.java
b/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/it/GetEaceServiceIT.java
new file mode 100644
index 0000000..03fce5b
--- /dev/null
+++
b/src/test/java/org/apache/sling/jcr/jackrabbit/accessmanager/it/GetEaceServiceIT.java
@@ -0,0 +1,225 @@
+/*
+ * 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.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager.it;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.fail;
+
+import java.util.Collections;
+
+import javax.inject.Inject;
+import javax.jcr.Node;
+import javax.jcr.PropertyType;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.SimpleCredentials;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.json.JsonObject;
+
+import
org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.apache.sling.api.resource.ResourceNotFoundException;
+import org.apache.sling.jcr.api.SlingRepository;
+import org.apache.sling.jcr.jackrabbit.accessmanager.GetEffectiveAce;
+import org.apache.sling.jcr.jackrabbit.accessmanager.ModifyAce;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+
+/**
+ * Tests for the 'modifyAce' inproc service
+ */
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class GetEaceServiceIT extends AccessManagerClientTestSupport {
+
+ @Inject
+ private ModifyAce modifyAce;
+
+ @Inject
+ private GetEffectiveAce getEffectiveAce;
+
+ @Inject
+ protected SlingRepository repository;
+
+ protected Session adminSession;
+
+ private Node testNode;
+
+ @Before
+ public void setup() throws RepositoryException {
+ adminSession = repository.login(new SimpleCredentials("admin",
"admin".toCharArray()));
+ assertNotNull("Expected adminSession to not be null", adminSession);
+ testNode = adminSession.getRootNode().addNode("testNode");
+ adminSession.save();
+ }
+
+ @After
+ public void teardown() throws RepositoryException {
+ adminSession.refresh(false);
+ testNode.remove();
+ if (adminSession.hasPendingChanges()) {
+ adminSession.save();
+ }
+ adminSession.logout();
+ }
+
+ protected JsonObject ace(String path, String principalId) throws
RepositoryException {
+ assertNotNull(getEffectiveAce);
+ JsonObject aceObject = getEffectiveAce.getEffectiveAce(adminSession,
path, principalId);
+ assertNotNull(aceObject);
+ return aceObject;
+ }
+
+ protected JsonObject acePrivleges(String path, String principalId) throws
RepositoryException {
+ JsonObject ace = ace(path, principalId);
+ JsonObject privilegesObject = ace.getJsonObject("privileges");
+ assertNotNull(privilegesObject);
+ return privilegesObject;
+ }
+
+ private Value val(int type, String value) throws RepositoryException {
+ return adminSession.getValueFactory().createValue(value, type);
+ }
+ private Value[] vals(int type, String ... value) throws
RepositoryException {
+ Value[] values = new Value[value.length];
+ ValueFactory vf = adminSession.getValueFactory();
+ for (int i = 0; i < value.length; i++) {
+ values[i] = vf.createValue(value[i], type);
+ }
+ return values;
+ }
+
+ @Test
+ public void testGetAceWithPrivileges() throws RepositoryException {
+ assertNotNull(modifyAce);
+ modifyAce.modifyAce(adminSession,
+ testNode.getPath(),
+ "everyone",
+ Collections.singletonMap(PrivilegeConstants.JCR_READ, "allow"),
+ "first");
+ // autosaved, so nothing should be pending
+ assertFalse(adminSession.hasPendingChanges());
+
+ JsonObject aceObject = ace(testNode.getPath(), "everyone");
+
+ JsonObject privilegesObject = aceObject.getJsonObject("privileges");
+ assertNotNull(privilegesObject);
+ assertEquals(1, privilegesObject.size());
+ //allow
+ assertPrivilege(privilegesObject, true, PrivilegeValues.ALLOW,
PrivilegeConstants.JCR_READ);
+ }
+
+ @Test
+ public void testGetAceWithRestrictions() throws RepositoryException {
+ assertNotNull(modifyAce);
+ modifyAce.modifyAce(adminSession,
+ testNode.getPath(),
+ "everyone",
+ Collections.singletonMap(PrivilegeConstants.JCR_READ, "allow"),
+ "first",
+ Collections.singletonMap(AccessControlConstants.REP_GLOB,
val(PropertyType.STRING, "/hello")),
+
Collections.singletonMap(AccessControlConstants.REP_ITEM_NAMES,
vals(PropertyType.NAME, "child1", "child2")),
+ Collections.emptySet());
+ // autosaved, so should be nothing pending
+ assertFalse(adminSession.hasPendingChanges());
+
+ JsonObject aceObject = ace(testNode.getPath(), "everyone");
+
+ JsonObject privilegesObject = aceObject.getJsonObject("privileges");
+ assertNotNull(privilegesObject);
+ assertEquals(1, privilegesObject.size());
+ //allow
+ assertPrivilege(privilegesObject, true, PrivilegeValues.ALLOW,
PrivilegeConstants.JCR_READ);
+ }
+
+ @Test
+ public void testGetAceWithNullSessionArg() throws RepositoryException {
+ assertNotNull(modifyAce);
+ String resourcePath = testNode.getPath();
+ try {
+ getEffectiveAce.getEffectiveAce(null,
+ resourcePath,
+ "everyone");
+ fail("Expected RepositoryException");
+ } catch (RepositoryException re) {
+ assertEquals("JCR Session not found", re.getMessage());
+ }
+ }
+
+ @Test
+ public void testGetAceWithNullResourcePathArg() throws RepositoryException
{
+ assertNotNull(modifyAce);
+ try {
+ getEffectiveAce.getEffectiveAce(adminSession,
+ null,
+ "everyone");
+ fail("Expected ResourceNotFoundException");
+ } catch (ResourceNotFoundException rnfe) {
+ //expected
+ }
+ }
+
+ @Test
+ public void testGetAceWithNotExistingResourcePathArg() throws
RepositoryException {
+ assertNotNull(modifyAce);
+ try {
+ getEffectiveAce.getEffectiveAce(adminSession,
+ "/not_a_real_path",
+ "everyone");
+ fail("Expected ResourceNotFoundException");
+ } catch (ResourceNotFoundException rnfe) {
+ //expected
+ }
+ }
+
+ @Test
+ public void testGetAceWithNullPrincipalIdArg() throws RepositoryException {
+ assertNotNull(modifyAce);
+ String resourcePath = testNode.getPath();
+ try {
+ getEffectiveAce.getEffectiveAce(adminSession,
+ resourcePath,
+ null);
+ fail("Expected RepositoryException");
+ } catch (RepositoryException re) {
+ assertEquals("principalId was not submitted.", re.getMessage());
+ }
+ }
+
+ @Test
+ public void testGetAceWithNotExistingPrincipalIdArg() throws
RepositoryException {
+ assertNotNull(modifyAce);
+ String resourcePath = testNode.getPath();
+ try {
+ getEffectiveAce.getEffectiveAce(adminSession,
+ resourcePath,
+ "not_a_real_principalid");
+ fail("Expected RepositoryException");
+ } catch (RepositoryException re) {
+ assertEquals("Invalid principalId was submitted.",
re.getMessage());
+ }
+ }
+
+}