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-contentloader.git
The following commit(s) were added to refs/heads/master by this push:
new 3dd6a2d SLING-11713 Change ACL json input structure (#17)
3dd6a2d is described below
commit 3dd6a2dee2ac5c4c0d9432161552796188eb1361
Author: Eric Norman <[email protected]>
AuthorDate: Sat Dec 10 12:22:37 2022 -0800
SLING-11713 Change ACL json input structure (#17)
to be less ambiguous for restrictions
---
.../sling/jcr/contentloader/ContentCreator.java | 25 +
.../sling/jcr/contentloader/LocalPrivilege.java | 144 +++++
.../sling/jcr/contentloader/LocalRestriction.java | 107 ++++
.../internal/DefaultContentCreator.java | 426 ++++++++++++-
.../contentloader/internal/readers/JsonReader.java | 261 +++++---
.../jcr/contentloader/ContentCreatorTest.java | 118 ++++
.../jcr/contentloader/LocalPrivilegeTest.java | 328 ++++++++++
.../jcr/contentloader/LocalRestrictionTest.java | 183 ++++++
.../internal/DefaultContentCreatorTest.java | 674 ++++++++++++++++++++-
.../jcr/contentloader/internal/JsonReaderTest.java | 53 +-
.../contentloader/it/ContentloaderTestSupport.java | 16 +
.../it/SLING11713InitialContentIT.java | 289 +++++++++
.../resources/initial-content/SLING-11713.json | 80 +++
13 files changed, 2588 insertions(+), 116 deletions(-)
diff --git
a/src/main/java/org/apache/sling/jcr/contentloader/ContentCreator.java
b/src/main/java/org/apache/sling/jcr/contentloader/ContentCreator.java
index 47195fd..6ebc3e4 100644
--- a/src/main/java/org/apache/sling/jcr/contentloader/ContentCreator.java
+++ b/src/main/java/org/apache/sling/jcr/contentloader/ContentCreator.java
@@ -19,6 +19,7 @@
package org.apache.sling.jcr.contentloader;
import java.io.InputStream;
+import java.util.Collection;
import java.util.Map;
import java.util.Set;
@@ -197,12 +198,36 @@ public interface ContentCreator {
* @param mvRestrictions specifies additional Map of multi-value
restrictions to apply. (optional)
* @param removedRestrictionNames optional set of restriction names that
should be removed (if they already exist).
* @throws RepositoryException If anything goes wrong.
+ * @deprecated use {@link #createAce(String, Collection, String)} instead
*/
+ @Deprecated
default void createAce(String principal, String[] grantedPrivileges,
String[] deniedPrivileges, String order,
Map<String, Value> restrictions, Map<String, Value[]>
mvRestrictions, Set<String> removedRestrictionNames) throws RepositoryException
{
throw new UnsupportedOperationException();
}
+ /**
+ * Creates an Access Control Entry for the current node for the specified
+ * principal and privileges.
+ *
+ * @param principal the user or group id for the ACE
+ * @param privileges the set of privileges to allow or deny for the
principal
+ * @param order specifies the position of the ACE in the
containing ACL. (may be null)
+ * Value should be one of these:
+ * <table>
+ * <caption>Values</caption>
+ * <tr><td>first</td><td>Place the target ACE as
the first amongst its siblings</td></tr>
+ * <tr><td>last</td><td>Place the target ACE as
the last amongst its siblings</td></tr>
+ * <tr><td>before xyz</td><td>Place the target
ACE immediately before the sibling whose name is xyz</td></tr>
+ * <tr><td>after xyz</td><td>Place the target ACE
immediately after the sibling whose name is xyz</td></tr>
+ * <tr><td>numeric</td><td>Place the target ACE
at the specified index</td></tr>
+ * </table>
+ * @throws RepositoryException If anything goes wrong.
+ */
+ default void createAce(String principal, Collection<LocalPrivilege>
privileges, String order) throws RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
/**
* Gets the current parent Node
* @return the current parent node or null
diff --git
a/src/main/java/org/apache/sling/jcr/contentloader/LocalPrivilege.java
b/src/main/java/org/apache/sling/jcr/contentloader/LocalPrivilege.java
new file mode 100644
index 0000000..51cae09
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/contentloader/LocalPrivilege.java
@@ -0,0 +1,144 @@
+/*
+ * 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.contentloader;
+
+import java.util.Collections;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.Privilege;
+
+public class LocalPrivilege {
+ private String privilegeName;
+ private boolean allow;
+ private boolean deny;
+ private Set<LocalRestriction> allowRestrictions = Collections.emptySet();
+ private Set<LocalRestriction> denyRestrictions = Collections.emptySet();
+ private Privilege privilege;
+
+ public LocalPrivilege(String privilege) {
+ this.privilegeName = privilege;
+ }
+
+ public void checkPrivilege(AccessControlManager acm) throws
RepositoryException {
+ this.privilege = acm.privilegeFromName(this.privilegeName);
+ }
+
+ public Privilege getPrivilege() {
+ return this.privilege;
+ }
+
+ public String getName() {
+ return privilegeName;
+ }
+
+ public boolean isAllow() {
+ return allow;
+ }
+
+ public boolean isDeny() {
+ return deny;
+ }
+
+ public void setAllow(boolean allow) {
+ this.allow = allow;
+ }
+
+ public void setDeny(boolean deny) {
+ this.deny = deny;
+ }
+
+ public Set<LocalRestriction> getAllowRestrictions() {
+ return allowRestrictions;
+ }
+
+ public void setAllowRestrictions(Set<LocalRestriction> allowRestrictions) {
+ this.allowRestrictions = allowRestrictions;
+ }
+
+ public Set<LocalRestriction> getDenyRestrictions() {
+ return denyRestrictions;
+ }
+
+ public void setDenyRestrictions(Set<LocalRestriction> denyRestrictions) {
+ this.denyRestrictions = denyRestrictions;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("LocalPrivilege [privilege=");
+ builder.append(privilegeName);
+ builder.append(", allow=");
+ builder.append(allow);
+ builder.append(", deny=");
+ builder.append(deny);
+ builder.append(", allowRestrictions=");
+ builder.append(allowRestrictions);
+ builder.append(", denyRestrictions=");
+ builder.append(denyRestrictions);
+ builder.append("]");
+ return builder.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (allow ? 1231 : 1237);
+ result = prime * result + ((allowRestrictions == null) ? 0 :
allowRestrictions.hashCode());
+ result = prime * result + (deny ? 1231 : 1237);
+ result = prime * result + ((denyRestrictions == null) ? 0 :
denyRestrictions.hashCode());
+ result = prime * result + ((privilegeName == null) ? 0 :
privilegeName.hashCode());
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ LocalPrivilege other = (LocalPrivilege) obj;
+ if (allow != other.allow)
+ return false;
+ if (allowRestrictions == null) {
+ if (other.allowRestrictions != null)
+ return false;
+ } else if (!allowRestrictions.equals(other.allowRestrictions))
+ return false;
+ if (deny != other.deny)
+ return false;
+ if (denyRestrictions == null) {
+ if (other.denyRestrictions != null)
+ return false;
+ } else if (!denyRestrictions.equals(other.denyRestrictions))
+ return false;
+ if (privilegeName == null) {
+ if (other.privilegeName != null)
+ return false;
+ } else if (!privilegeName.equals(other.privilegeName))
+ return false;
+ return true;
+ }
+
+}
diff --git
a/src/main/java/org/apache/sling/jcr/contentloader/LocalRestriction.java
b/src/main/java/org/apache/sling/jcr/contentloader/LocalRestriction.java
new file mode 100644
index 0000000..26a886b
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/contentloader/LocalRestriction.java
@@ -0,0 +1,107 @@
+/*
+ * 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.contentloader;
+
+import java.util.Arrays;
+
+import javax.jcr.Value;
+
+import org.jetbrains.annotations.NotNull;
+
+public class LocalRestriction {
+ private String restriction;
+ private boolean multival;
+ private Value[] values;
+
+ public LocalRestriction(@NotNull String restriction, Value[] values) {
+ this.restriction = restriction;
+ this.multival = true;
+ this.values = values;
+ }
+
+ public LocalRestriction(@NotNull String restriction, Value value) {
+ super();
+ this.restriction = restriction;
+ this.multival = false;
+ this.values = value == null ? null : new Value[] {value};
+ }
+
+ public String getName() {
+ return restriction;
+ }
+
+ public boolean isMultiValue() {
+ return multival;
+ }
+
+ public Value getValue() {
+ Value v = null;
+ if (values != null && values.length > 0) {
+ v = values[0];
+ }
+ return v;
+ }
+
+ public Value[] getValues() {
+ return values;
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder builder = new StringBuilder();
+ builder.append("LocalRestriction [restriction=");
+ builder.append(restriction);
+ builder.append(", multival=");
+ builder.append(multival);
+ builder.append(", values=");
+ builder.append(Arrays.toString(values));
+ builder.append("]");
+ return builder.toString();
+ }
+
+ @Override
+ public int hashCode() {
+ final int prime = 31;
+ int result = 1;
+ result = prime * result + (multival ? 1231 : 1237);
+ result = prime * result + ((restriction == null) ? 0 :
restriction.hashCode());
+ result = prime * result + Arrays.hashCode(values);
+ return result;
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ if (this == obj)
+ return true;
+ if (obj == null)
+ return false;
+ if (getClass() != obj.getClass())
+ return false;
+ LocalRestriction other = (LocalRestriction) obj;
+ if (multival != other.multival)
+ return false;
+ if (restriction == null) {
+ if (other.restriction != null)
+ return false;
+ } else if (!restriction.equals(other.restriction))
+ return false;
+ return Arrays.equals(values, other.values);
+ }
+
+}
diff --git
a/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
b/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
index 8d2e7b0..ec1eb8f 100644
---
a/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
+++
b/src/main/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreator.java
@@ -26,10 +26,13 @@ import java.security.Principal;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.Calendar;
+import java.util.Collection;
import java.util.Collections;
import java.util.Date;
import java.util.Deque;
import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
@@ -50,21 +53,35 @@ import javax.jcr.PropertyIterator;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
import javax.jcr.Value;
import javax.jcr.ValueFactory;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlException;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.AccessControlPolicyIterator;
+import javax.jcr.security.Privilege;
import javax.jcr.version.VersionManager;
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlList;
import org.apache.jackrabbit.api.security.principal.PrincipalManager;
import org.apache.jackrabbit.api.security.user.Authorizable;
import org.apache.jackrabbit.api.security.user.Group;
import org.apache.jackrabbit.api.security.user.User;
import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
import org.apache.jackrabbit.util.ISO8601;
import org.apache.sling.jcr.base.util.AccessControlUtil;
import org.apache.sling.jcr.contentloader.ContentCreator;
import org.apache.sling.jcr.contentloader.ContentImportListener;
import org.apache.sling.jcr.contentloader.ContentReader;
import org.apache.sling.jcr.contentloader.ImportOptions;
+import org.apache.sling.jcr.contentloader.LocalPrivilege;
+import org.apache.sling.jcr.contentloader.LocalRestriction;
+import org.jetbrains.annotations.NotNull;
+import org.jetbrains.annotations.Nullable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -842,26 +859,88 @@ public class DefaultContentCreator implements
ContentCreator {
*/
public void createAce(String principalId, String[] grantedPrivilegeNames,
String[] deniedPrivilegeNames,
String order) throws RepositoryException {
- createAce(principalId, grantedPrivilegeNames, deniedPrivilegeNames,
order, null, null, null);
+ Map<String, LocalPrivilege> privilegeToLocalPrivilegesMap =
toLocalPrivileges(grantedPrivilegeNames,
+ deniedPrivilegeNames);
+
+ createAce(principalId, new
ArrayList<>(privilegeToLocalPrivilegesMap.values()), order);
}
- /*
- * (non-Javadoc)
+ /**
+ * Convert the privilege names to LocalPrivileges
*
- * @see
- *
org.apache.sling.jcr.contentloader.ContentCreator#createAce(java.lang.String,
- * java.lang.String[], java.lang.String[], java.lang.String, java.util.Map,
- * java.util.Map, java.util.Set)
+ * @param grantedPrivilegeNames the granted privileges
+ * @param deniedPrivilegeNames the denied privileges
+ * @return map of privilege names to LocalPrivilege data
+ */
+ protected Map<String, LocalPrivilege> toLocalPrivileges(String[]
grantedPrivilegeNames,
+ String[] deniedPrivilegeNames) {
+ // first start with an empty map
+ Map<String, LocalPrivilege> privilegeToLocalPrivilegesMap = new
LinkedHashMap<>();
+
+ if (grantedPrivilegeNames != null) {
+ for (String pn: grantedPrivilegeNames) {
+ LocalPrivilege lp =
privilegeToLocalPrivilegesMap.computeIfAbsent(pn, LocalPrivilege::new);
+ lp.setAllow(true);
+ }
+ }
+
+ if (deniedPrivilegeNames != null) {
+ for (String pn: deniedPrivilegeNames) {
+ LocalPrivilege lp =
privilegeToLocalPrivilegesMap.computeIfAbsent(pn, LocalPrivilege::new);
+ lp.setDeny(true);
+ }
+ }
+ return privilegeToLocalPrivilegesMap;
+ }
+
+ /**
+ * @deprecated use {@link #createAce(String, Collection, String)} instead
*/
+ @Deprecated
@Override
public void createAce(String principalId, String[] grantedPrivilegeNames,
String[] deniedPrivilegeNames,
String order, Map<String, Value> restrictions, Map<String,
Value[]> mvRestrictions,
Set<String> removedRestrictionNames) throws RepositoryException {
+ Map<String, LocalPrivilege> privilegeToLocalPrivilegesMap =
toLocalPrivileges(grantedPrivilegeNames,
+ deniedPrivilegeNames);
+
+ Set<LocalRestriction> restrictionsSet = new HashSet<>();
+ if (restrictions != null) {
+ for (Entry<String, Value> entry: restrictions.entrySet()) {
+ LocalRestriction lr = new LocalRestriction(entry.getKey(),
entry.getValue());
+ restrictionsSet.add(lr);
+ }
+ }
+ if (mvRestrictions != null) {
+ for (Entry<String, Value[]> entry: mvRestrictions.entrySet()) {
+ LocalRestriction lr = new LocalRestriction(entry.getKey(),
entry.getValue());
+ restrictionsSet.add(lr);
+ }
+ }
+
+ if (!restrictionsSet.isEmpty()) {
+ for (LocalPrivilege entry: privilegeToLocalPrivilegesMap.values())
{
+ if (entry.isAllow()) {
+ entry.setAllowRestrictions(restrictionsSet);
+ }
+ if (entry.isDeny()) {
+ entry.setDenyRestrictions(restrictionsSet);
+ }
+ }
+ }
+
+ createAce(principalId, new
ArrayList<>(privilegeToLocalPrivilegesMap.values()), order);
+ }
+
+ @Override
+ public void createAce(String principalId, Collection<LocalPrivilege>
privileges, String order)
+ throws RepositoryException {
final Node parentNode = this.parentNodeStack.peek();
- Session session = parentNode.getSession();
+ Session jcrSession = parentNode.getSession();
- PrincipalManager principalManager =
AccessControlUtil.getPrincipalManager(session);
- Principal principal = principalManager.getPrincipal(principalId);
+ // validate that the principal name is valid
+ PrincipalManager principalManager =
AccessControlUtil.getPrincipalManager(jcrSession);
+ Principal principal = principalId == null ? null :
principalManager.getPrincipal(principalId);
if (principal == null) {
// SLING-7268 - as pointed out in OAK-5496, we cannot successfully
use
// PrincipalManager#getPrincipal in oak
@@ -869,7 +948,7 @@ public class DefaultContentCreator implements
ContentCreator {
// subsequent index update).
// Workaround by trying the UserManager#getAuthorizable API to
locate the
// principal.
- UserManager userManager =
AccessControlUtil.getUserManager(session);
+ UserManager userManager =
AccessControlUtil.getUserManager(jcrSession);
final Authorizable authorizable =
userManager.getAuthorizable(principalId);
if (authorizable != null) {
principal = authorizable.getPrincipal();
@@ -879,11 +958,330 @@ public class DefaultContentCreator implements
ContentCreator {
if (principal == null) {
throw new RepositoryException("No principal found for id: " +
principalId);
}
+
+ // validate that the privilege names are valid
+ AccessControlManager acm =
AccessControlUtil.getAccessControlManager(jcrSession);
+ for (LocalPrivilege localPrivilege: privileges) {
+ localPrivilege.checkPrivilege(acm);
+ }
+
String resourcePath = parentNode.getPath();
- if ((grantedPrivilegeNames != null) || (deniedPrivilegeNames != null))
{
- AccessControlUtil.replaceAccessControlEntry(session, resourcePath,
principal, grantedPrivilegeNames, deniedPrivilegeNames, null, order,
- restrictions, mvRestrictions, removedRestrictionNames);
+ // build a list of each of the LocalPrivileges that have the same
restrictions
+ Map<Set<LocalRestriction>, List<LocalPrivilege>>
allowRestrictionsToLocalPrivilegesMap = new HashMap<>();
+ Map<Set<LocalRestriction>, List<LocalPrivilege>>
denyRestrictionsToLocalPrivilegesMap = new HashMap<>();
+ for (LocalPrivilege localPrivilege: privileges) {
+ if (localPrivilege.isAllow()) {
+ List<LocalPrivilege> list =
allowRestrictionsToLocalPrivilegesMap.computeIfAbsent(localPrivilege.getAllowRestrictions(),
key -> new ArrayList<>());
+ list.add(localPrivilege);
+ }
+ if (localPrivilege.isDeny()) {
+ List<LocalPrivilege> list =
denyRestrictionsToLocalPrivilegesMap.computeIfAbsent(localPrivilege.getDenyRestrictions(),
key -> new ArrayList<>());
+ list.add(localPrivilege);
+ }
+ }
+
+ try {
+ // Get or create the ACL for the node.
+ JackrabbitAccessControlList acl = getAcl(acm, resourcePath,
principal);
+
+ // remove all the old aces for the principal
+ order = removeAces(resourcePath, order, principal, acl);
+
+ // now add all the new aces that we have collected
+ Map<Privilege, Integer> privilegeLongestDepthMap =
buildPrivilegeLongestDepthMap(acm.privilegeFromName(PrivilegeConstants.JCR_ALL));
+ addAces(resourcePath, principal,
denyRestrictionsToLocalPrivilegesMap, false, acl, privilegeLongestDepthMap);
+ addAces(resourcePath, principal,
allowRestrictionsToLocalPrivilegesMap, true, acl, privilegeLongestDepthMap);
+
+ // reorder the aces
+ reorderAccessControlEntries(acl, principal, order);
+
+ // Store the actual changes.
+ acm.setPolicy(acl.getPath(), acl);
+ } catch (RepositoryException re) {
+ throw new RepositoryException("Failed to create ace.", re);
+ }
+ }
+
+ /**
+ * If the privilege is contained in multiple aggregate privileges, then
+ * calculate the instance with the greatest depth.
+ */
+ private static void toLongestDepth(int parentDepth, Privilege
parentPrivilege, Map<Privilege, Integer> privilegeToLongestDepth) {
+ Privilege[] declaredAggregatePrivileges =
parentPrivilege.getDeclaredAggregatePrivileges();
+ for (Privilege privilege : declaredAggregatePrivileges) {
+ Integer oldValue = privilegeToLongestDepth.get(privilege);
+ int candidateDepth = parentDepth + 1;
+ if (oldValue == null || oldValue.intValue() < candidateDepth) {
+ privilegeToLongestDepth.put(privilege, candidateDepth);
+
+ // continue drilling down to the leaf privileges
+ toLongestDepth(candidateDepth, privilege,
privilegeToLongestDepth);
+ }
+ }
+ }
+
+ /**
+ * Calculate the longest path for each of the possible privileges
+ *
+ * @param jcrSession the current users JCR session
+ * @return map where the key is the privilege and the value is the longest
path
+ */
+ public static Map<Privilege, Integer>
buildPrivilegeLongestDepthMap(Privilege jcrAll) {
+ Map<Privilege, Integer> privilegeToLongestPath = new HashMap<>();
+ privilegeToLongestPath.put(jcrAll, 1);
+ toLongestDepth(1, jcrAll, privilegeToLongestPath);
+ return privilegeToLongestPath;
+ }
+
+ /**
+ * Lookup the ACL for the given resource
+ *
+ * @param acm the access control manager
+ * @param resourcePath the resource path
+ * @param principal the principal for principalbased ACL
+ * @return the found ACL object
+ */
+ protected JackrabbitAccessControlList getAcl(@NotNull AccessControlManager
acm, String resourcePath, Principal principal)
+ throws RepositoryException {
+ AccessControlPolicy[] policies = acm.getPolicies(resourcePath);
+ JackrabbitAccessControlList acl = null;
+ for (AccessControlPolicy policy : policies) {
+ if (policy instanceof JackrabbitAccessControlList) {
+ acl = (JackrabbitAccessControlList) policy;
+ break;
+ }
+ }
+ if (acl == null) {
+ AccessControlPolicyIterator applicablePolicies =
acm.getApplicablePolicies(resourcePath);
+ while (applicablePolicies.hasNext()) {
+ AccessControlPolicy policy =
applicablePolicies.nextAccessControlPolicy();
+ if (policy instanceof JackrabbitAccessControlList) {
+ acl = (JackrabbitAccessControlList) policy;
+ break;
+ }
+ }
+ }
+ return acl;
+ }
+
+ /**
+ * Remove all of the ACEs for the specified principal from the ACL
+ *
+ * @param order the requested order (may be null)
+ * @param principal the principal whose aces should be removed
+ * @param acl the access control list to update
+ * @return the original order if it was supplied, otherwise the order of
the first ACE
+ */
+ protected String removeAces(@NotNull String resourcePath, @Nullable String
order, @NotNull Principal principal, @NotNull JackrabbitAccessControlList acl)
// NOSONAR
+ throws RepositoryException {
+ AccessControlEntry[] existingAccessControlEntries =
acl.getAccessControlEntries();
+
+ if (order == null || order.length() == 0) {
+ //order not specified, so keep track of the original ACE position.
+ Set<Principal> processedPrincipals = new HashSet<>();
+ for (int j = 0; j < existingAccessControlEntries.length; j++) {
+ AccessControlEntry ace = existingAccessControlEntries[j];
+ Principal principal2 = ace.getPrincipal();
+ if (principal2.equals(principal)) {
+ order = String.valueOf(processedPrincipals.size());
+ break;
+ } else {
+ processedPrincipals.add(principal2);
+ }
+ }
+ }
+
+ for (int j = 0; j < existingAccessControlEntries.length; j++) {
+ AccessControlEntry ace = existingAccessControlEntries[j];
+ if (ace.getPrincipal().equals(principal)) {
+ acl.removeAccessControlEntry(ace);
+ }
+ }
+ return order;
+ }
+
+ /**
+ * Add ACEs for the specified principal to the ACL. One ACE is added for
each unique
+ * restriction set.
+ *
+ * @param resourcePath the path of the resource
+ * @param principal the principal whose aces should be added
+ * @param restrictionsToLocalPrivilegesMap the map containing the
restrictions mapped to the LocalPrivlege items with those resrictions
+ * @param isAllow true for 'allow' ACE, false for 'deny' ACE
+ * @param acl the access control list to update
+ */
+ protected void addAces(@NotNull String resourcePath, @NotNull Principal
principal,
+ @NotNull Map<Set<LocalRestriction>, List<LocalPrivilege>>
restrictionsToLocalPrivilegesMap,
+ boolean isAllow,
+ @NotNull JackrabbitAccessControlList acl,
+ Map<Privilege, Integer> privilegeLongestDepthMap) throws
RepositoryException {
+
+ List<Entry<Set<LocalRestriction>, List<LocalPrivilege>>> sortedEntries
= new ArrayList<>(restrictionsToLocalPrivilegesMap.entrySet());
+ // sort the entries by the most shallow depth of the contained
privileges
+ Collections.sort(sortedEntries, (e1, e2) -> {
+ int shallowestDepth1 = Integer.MAX_VALUE;
+ for (LocalPrivilege lp : e1.getValue()) {
+ Integer depth =
privilegeLongestDepthMap.get(lp.getPrivilege());
+ if (depth != null && depth.intValue() <
shallowestDepth1) {
+ shallowestDepth1 = depth.intValue();
+ }
+ }
+ int shallowestDepth2 = Integer.MAX_VALUE;
+ for (LocalPrivilege lp : e2.getValue()) {
+ Integer depth =
privilegeLongestDepthMap.get(lp.getPrivilege());
+ if (depth != null && depth.intValue() <
shallowestDepth2) {
+ shallowestDepth2 = depth.intValue();
+ }
+ }
+ return Integer.compare(shallowestDepth1,
shallowestDepth2);
+ });
+
+ for (Entry<Set<LocalRestriction>, List<LocalPrivilege>> entry:
sortedEntries) {
+ Set<Privilege> privilegesSet = new HashSet<>();
+ Map<String, Value> restrictions = new HashMap<>();
+ Map<String, Value[]> mvRestrictions = new HashMap<>();
+
+ Set<LocalRestriction> localRestrictions = entry.getKey();
+ for (LocalRestriction localRestriction : localRestrictions) {
+ if (localRestriction.isMultiValue()) {
+ mvRestrictions.put(localRestriction.getName(),
localRestriction.getValues());
+ } else {
+ restrictions.put(localRestriction.getName(),
localRestriction.getValue());
+ }
+ }
+
+ for (LocalPrivilege localPrivilege : entry.getValue()) {
+ privilegesSet.add(localPrivilege.getPrivilege());
+ }
+
+ if (!privilegesSet.isEmpty()) {
+ acl.addEntry(principal, privilegesSet.toArray(new
Privilege[privilegesSet.size()]), isAllow, restrictions, mvRestrictions);
+ }
+ }
+ }
+
+ /**
+ * Move the ACE(s) for the specified principal to the position specified
by the 'order'
+ * parameter. This is a copy of the private
AccessControlUtil.reorderAccessControlEntries method.
+ *
+ * @param acl the acl of the node containing the ACE to position
+ * @param principal the user or group of the ACE to position
+ * @param order where the access control entry should go in the list.
+ * Value should be one of these:
+ * <table>
+ * <caption>Values</caption>
+ * <tr><td>first</td><td>Place the target ACE as the first
amongst its siblings</td></tr>
+ * <tr><td>last</td><td>Place the target ACE as the last amongst
its siblings</td></tr>
+ * <tr><td>before xyz</td><td>Place the target ACE immediately
before the sibling whose name is xyz</td></tr>
+ * <tr><td>after xyz</td><td>Place the target ACE immediately
after the sibling whose name is xyz</td></tr>
+ * <tr><td>numeric</td><td>Place the target ACE at the specified
index</td></tr>
+ * </table>
+ * @throws RepositoryException
+ * @throws UnsupportedRepositoryOperationException
+ * @throws AccessControlException
+ */
+ private static void reorderAccessControlEntries(AccessControlList acl,
+ Principal principal, String order) throws RepositoryException {
+ if (order == null || order.length() == 0) {
+ return; //nothing to do
+ }
+ if (acl instanceof JackrabbitAccessControlList) {
+ JackrabbitAccessControlList jacl =
(JackrabbitAccessControlList)acl;
+
+ AccessControlEntry[] accessControlEntries =
jacl.getAccessControlEntries();
+ if (accessControlEntries.length <= 1) {
+ return; //only one ACE, so nothing to reorder.
+ }
+
+ AccessControlEntry beforeEntry = null;
+ if ("first".equals(order)) {
+ beforeEntry = accessControlEntries[0];
+ } else if ("last".equals(order)) {
+ // add to the end is the same as default
+ } else if (order.startsWith("before ")) {
+ String beforePrincipalName = order.substring(7);
+
+ //find the index of the ACE of the 'before' principal
+ for (int i=0; i < accessControlEntries.length; i++) {
+ if
(beforePrincipalName.equals(accessControlEntries[i].getPrincipal().getName())) {
+ //found it!
+ beforeEntry = accessControlEntries[i];
+ break;
+ }
+ }
+
+ if (beforeEntry == null) {
+ //didn't find an ACE that matched the 'before' principal
+ throw new IllegalArgumentException("No ACE was found for
the specified principal: " + beforePrincipalName);
+ }
+ } else if (order.startsWith("after ")) {
+ String afterPrincipalName = order.substring(6);
+
+ boolean foundPrincipal = false;
+ //find the index of the ACE of the 'after' principal
+ for (int i = accessControlEntries.length - 1; i >= 0; i--) {
+ if
(afterPrincipalName.equals(accessControlEntries[i].getPrincipal().getName())) {
+ //found it!
+ foundPrincipal = true;
+
+ // the 'before' ACE is the next one after the 'after'
ACE
+ if (i >= accessControlEntries.length - 1) {
+ //the after is the last one in the list
+ beforeEntry = null;
+ } else {
+ beforeEntry = accessControlEntries[i + 1];
+ }
+ break;
+ }
+ }
+
+ if (!foundPrincipal) {
+ //didn't find an ACE that matched the 'after' principal
+ throw new IllegalArgumentException("No ACE was found for
the specified principal: " + afterPrincipalName);
+ }
+ } else {
+ int index = -1;
+ try {
+ index = Integer.parseInt(order);
+ } catch (NumberFormatException nfe) {
+ //not a number.
+ throw new IllegalArgumentException("Illegal value for the
order parameter: " + order);
+ }
+ if (index > accessControlEntries.length) {
+ //invalid index
+ throw new IndexOutOfBoundsException("Index value is too
large: " + index);
+ }
+
+ //the index value is the index of the principal. A principal
may have more
+ // than one ACEs (deny + grant), so we need to compensate.
+ Map<Principal, Integer> principalToIndex = new HashMap<>();
+ for (int i = 0; i < accessControlEntries.length; i++) {
+ Principal principal2 =
accessControlEntries[i].getPrincipal();
+ Integer idx = i;
+ principalToIndex.computeIfAbsent(principal2, key -> idx);
+ }
+ Integer[] sortedIndexes = principalToIndex.values().stream()
+ .sorted()
+ .toArray(size -> new Integer[size]);
+ if (index >= 0 && index < sortedIndexes.length - 1) {
+ int idx = sortedIndexes[index];
+ beforeEntry = accessControlEntries[idx];
+ }
+ }
+
+ if (beforeEntry != null) {
+ //now loop through the entries to move the affected ACEs to
the specified
+ // position.
+ for (AccessControlEntry ace : accessControlEntries) {
+ if (principal.equals(ace.getPrincipal())) {
+ //this ACE is for the specified principal.
+ jacl.orderBefore(ace, beforeEntry);
+ }
+ }
+ }
+ } else {
+ throw new IllegalArgumentException("The acl must be an instance of
JackrabbitAccessControlList");
}
}
diff --git
a/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/JsonReader.java
b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/JsonReader.java
index 7bd0617..47494b0 100644
---
a/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/JsonReader.java
+++
b/src/main/java/org/apache/sling/jcr/contentloader/internal/readers/JsonReader.java
@@ -25,10 +25,14 @@ import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringReader;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
import java.util.regex.Pattern;
@@ -47,14 +51,18 @@ import jakarta.json.JsonString;
import jakarta.json.JsonValue;
import jakarta.json.JsonValue.ValueType;
+import
org.apache.jackrabbit.oak.spi.security.authorization.restriction.CompositeRestrictionProvider;
import
org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionDefinition;
import
org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
import org.apache.sling.jcr.contentloader.ContentCreator;
import org.apache.sling.jcr.contentloader.ContentReader;
+import org.apache.sling.jcr.contentloader.LocalPrivilege;
+import org.apache.sling.jcr.contentloader.LocalRestriction;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleContext;
import org.osgi.framework.Constants;
import org.osgi.framework.FrameworkUtil;
+import org.osgi.framework.InvalidSyntaxException;
import org.osgi.framework.ServiceReference;
import org.osgi.service.component.annotations.Component;
@@ -465,128 +473,199 @@ public class JsonReader implements ContentReader {
*/
private void createAce(JsonObject ace, ContentCreator contentCreator)
throws RepositoryException {
String principalID = ace.getString("principal");
+ String order = ace.getString("order", null);
+
+ // first start with an empty map
+ Map<String, LocalPrivilege> privilegeToLocalPrivilegesMap = new
LinkedHashMap<>();
+
+ Node parentNode = contentCreator.getParent();
+ ValueFactory vf = parentNode.getSession().getValueFactory();
+
+ // Calculate a map of restriction names to the restriction definition.
+ // Use for fast lookup during the calls below.
+ Map<String, RestrictionDefinition> srMap = toSrMap(parentNode);
- String[] grantedPrivileges = null;
+ // for backward compatibility, process the older syntax
JsonArray granted = (JsonArray) ace.get("granted");
- if (granted != null) {
- grantedPrivileges = new String[granted.size()];
- for (int a = 0; a < grantedPrivileges.length; a++) {
- grantedPrivileges[a] = granted.getString(a);
+ JsonArray denied = (JsonArray) ace.get("denied");
+ if (granted != null || denied != null) {
+ JsonValue restrictions = ace.get("restrictions");
+ Set<LocalRestriction> restrictionsSet = Collections.emptySet();
+ if (restrictions instanceof JsonObject) {
+ restrictionsSet =
toLocalRestrictions((JsonObject)restrictions, srMap, vf);
+ }
+
+ if (granted != null) {
+ for (int a = 0; a < granted.size(); a++) {
+ String privilegeName = granted.getString(a);
+ LocalPrivilege lp =
privilegeToLocalPrivilegesMap.computeIfAbsent(privilegeName,
LocalPrivilege::new);
+ lp.setAllow(true);
+ lp.setAllowRestrictions(restrictionsSet);
+ }
+ }
+
+ if (denied != null) {
+ for (int a = 0; a < denied.size(); a++) {
+ String privilegeName = denied.getString(a);
+ LocalPrivilege lp =
privilegeToLocalPrivilegesMap.computeIfAbsent(privilegeName,
LocalPrivilege::new);
+ lp.setDeny(true);
+ lp.setDenyRestrictions(restrictionsSet);
+ }
}
}
- String[] deniedPrivileges = null;
- JsonArray denied = (JsonArray) ace.get("denied");
- if (denied != null) {
- deniedPrivileges = new String[denied.size()];
- for (int a = 0; a < deniedPrivileges.length; a++) {
- deniedPrivileges[a] = denied.getString(a);
+ // now process the newer syntax
+ JsonValue privileges = ace.get("privileges");
+ if (privileges instanceof JsonObject) {
+ JsonObject privilegesObj = (JsonObject)privileges;
+ for (Entry<String, JsonValue> entry : privilegesObj.entrySet()) {
+ String privilegeName = entry.getKey();
+ JsonValue privilegeValue = entry.getValue();
+ if (privilegeValue instanceof JsonObject) {
+ JsonObject privilegeValueObj = (JsonObject)privilegeValue;
+ JsonValue allow = privilegeValueObj.get("allow");
+ boolean isAllow = false;
+ Set<LocalRestriction> allowRestrictions =
Collections.emptySet();
+ if (allow instanceof JsonObject) {
+ isAllow = true;
+ allowRestrictions =
toLocalRestrictions((JsonObject)allow, srMap, vf);
+ } else if (JsonValue.TRUE.equals(allow)) {
+ isAllow = true;
+ }
+
+ JsonValue deny = privilegeValueObj.get("deny");
+ boolean isDeny = false;
+ Set<LocalRestriction> denyRestrictions =
Collections.emptySet();
+ if (deny instanceof JsonObject) {
+ isDeny = true;
+ denyRestrictions =
toLocalRestrictions((JsonObject)deny, srMap, vf);
+ } else if (JsonValue.TRUE.equals(deny)) {
+ isDeny = true;
+ }
+
+ if (isAllow || isDeny) {
+ LocalPrivilege lp =
privilegeToLocalPrivilegesMap.computeIfAbsent(privilegeName,
LocalPrivilege::new);
+ if (isAllow) {
+ lp.setAllow(true);
+ lp.setAllowRestrictions(allowRestrictions);
+ }
+ if (isDeny) {
+ lp.setDeny(true);
+ lp.setDenyRestrictions(denyRestrictions);
+ }
+ }
+ }
}
}
- String order = ace.getString("order", null);
+ // do the work.
+ contentCreator.createAce(principalID, new
ArrayList<>(privilegeToLocalPrivilegesMap.values()), order);
+ }
- Map<String, Value> restrictionsMap = null;
- Map<String, Value[]> mvRestrictionsMap = null;
- Set<String> removedRestrictionNames = null;
- JsonObject restrictions = (JsonObject) ace.get("restrictions");
- if (restrictions != null) {
- // lazy initialized map for quick lookup when processing
restrictions
- Map<String, RestrictionDefinition> supportedRestrictionsMap = new
HashMap<>();
+ /**
+ * Calculate a map of restriction names to the restriction definition
+ *
+ * @param parentNode the node the restrictions are for
+ */
+ protected Map<String, RestrictionDefinition> toSrMap(Node parentNode)
+ throws RepositoryException {
+ // lazy initialized map for quick lookup when processing restrictions
+ Map<String, RestrictionDefinition> supportedRestrictionsMap = new
HashMap<>();
- Node parentNode = contentCreator.getParent();
+ RestrictionProvider compositeRestrictionProvider = null;
+ Set<RestrictionProvider> restrictionProviders = new HashSet<>();
- RestrictionProvider restrictionProvider = null;
- Bundle bundle = FrameworkUtil.getBundle(getClass());
+ Bundle bundle = FrameworkUtil.getBundle(getClass());
+ if (bundle != null) {
BundleContext bundleContext = bundle.getBundleContext();
- ServiceReference<RestrictionProvider> serviceReference = null;
+ Collection<ServiceReference<RestrictionProvider>>
serviceReferences = null;
try {
- serviceReference =
bundleContext.getServiceReference(RestrictionProvider.class);
- restrictionProvider =
bundleContext.getService(serviceReference);
-
- if (restrictionProvider == null) {
- throw new JsonException(
- "No restriction provider is available so unable to
process restriction values");
+ serviceReferences =
bundleContext.getServiceReferences(RestrictionProvider.class, null);
+ for (ServiceReference<RestrictionProvider> serviceReference :
serviceReferences) {
+ RestrictionProvider service =
bundleContext.getService(serviceReference);
+ restrictionProviders.add(service);
}
+ compositeRestrictionProvider =
CompositeRestrictionProvider.newInstance(restrictionProviders);
// populate the map
- Set<RestrictionDefinition> supportedRestrictions =
restrictionProvider
+ Set<RestrictionDefinition> supportedRestrictions =
compositeRestrictionProvider
.getSupportedRestrictions(parentNode.getPath());
for (RestrictionDefinition restrictionDefinition :
supportedRestrictions) {
supportedRestrictionsMap.put(restrictionDefinition.getName(),
restrictionDefinition);
}
+ } catch (InvalidSyntaxException e) {
+ throw new RepositoryException(e);
} finally {
- if (serviceReference != null) {
- bundleContext.ungetService(serviceReference);
+ if (serviceReferences != null) {
+ for (ServiceReference<RestrictionProvider>
serviceReference : serviceReferences) {
+ bundleContext.ungetService(serviceReference);
+ }
}
}
+ }
+ return supportedRestrictionsMap;
+ }
- restrictionsMap = new HashMap<>();
- mvRestrictionsMap = new HashMap<>();
- removedRestrictionNames = new HashSet<>();
+ /**
+ * Construct a LocalRestriction using data from the json object
+ *
+ * @param allowOrDenyObj the json object
+ * @param srMap map of restriction names to the restriction definition
+ * @param vf the ValueFactory
+ */
+ protected Set<LocalRestriction> toLocalRestrictions(JsonObject
allowOrDenyObj,
+ Map<String, RestrictionDefinition> srMap,
+ ValueFactory vf) throws RepositoryException {
+ Set<LocalRestriction> restrictions = new HashSet<>();
+ for (Entry<String, JsonValue> restrictionEntry :
allowOrDenyObj.entrySet()) {
+ String restrictionName = restrictionEntry.getKey();
+ RestrictionDefinition rd = srMap.get(restrictionName);
+ if (rd == null) {
+ // illegal restriction name?
+ throw new JsonException("Invalid or not supported restriction
name was supplied: " + restrictionName);
+ }
- ValueFactory factory = parentNode.getSession().getValueFactory();
+ boolean multival = rd.getRequiredType().isArray();
+ int restrictionType = rd.getRequiredType().tag();
- Set<String> keySet = restrictions.keySet();
- for (String rname : keySet) {
- if (rname.endsWith("@Delete")) {
- // add the key to the 'remove' set. the value doesn't
matter and is ignored.
- String rname2 = rname.substring(9, rname.length() - 7);
- removedRestrictionNames.add(rname2);
- } else {
- RestrictionDefinition rd =
supportedRestrictionsMap.get(rname);
- if (rd == null) {
- // illegal restriction name?
- throw new JsonException("Invalid or not supported
restriction name was supplied: " + rname);
- }
+ LocalRestriction lr = null;
+ JsonValue jsonValue = restrictionEntry.getValue();
- boolean multival = rd.getRequiredType().isArray();
- int restrictionType = rd.getRequiredType().tag();
-
- // read the requested restriction value and apply it
- JsonValue jsonValue = restrictions.get(rname);
-
- if (multival) {
- if (jsonValue.getValueType() == ValueType.ARRAY) {
- JsonArray jsonArray = (JsonArray) jsonValue;
- int size = jsonArray.size();
- Value[] values = new Value[size];
- for (int i = 0; i < size; i++) {
- values[i] = toValue(factory, jsonArray.get(i),
restrictionType);
- }
- mvRestrictionsMap.put(rname, values);
- } else {
- Value v = toValue(factory, jsonValue,
restrictionType);
- mvRestrictionsMap.put(rname, new Value[] { v });
- }
- } else {
- if (jsonValue.getValueType() == ValueType.ARRAY) {
- JsonArray jsonArray = (JsonArray) jsonValue;
- int size = jsonArray.size();
- if (size == 1) {
- Value v = toValue(factory, jsonArray.get(0),
restrictionType);
- restrictionsMap.put(rname, v);
- } else if (size > 1) {
- throw new JsonException(
- "Unexpected multi value array data
found for single-value restriction value for name: "
- + rname);
- }
- } else {
- Value v = toValue(factory, jsonValue,
restrictionType);
- restrictionsMap.put(rname, v);
- }
+ if (multival) {
+ if (jsonValue.getValueType() == ValueType.ARRAY) {
+ JsonArray jsonArray = (JsonArray) jsonValue;
+ int size = jsonArray.size();
+ Value[] values = new Value[size];
+ for (int i = 0; i < size; i++) {
+ values[i] = toValue(vf, jsonArray.get(i),
restrictionType);
+ }
+ lr = new LocalRestriction(restrictionName, values);
+ } else {
+ Value v = toValue(vf, jsonValue, restrictionType);
+ lr = new LocalRestriction(restrictionName, new Value[] { v
});
+ }
+ } else {
+ if (jsonValue.getValueType() == ValueType.ARRAY) {
+ JsonArray jsonArray = (JsonArray) jsonValue;
+ int size = jsonArray.size();
+ if (size == 1) {
+ Value v = toValue(vf, jsonArray.get(0),
restrictionType);
+ lr = new LocalRestriction(restrictionName, v);
+ } else if (size > 1) {
+ throw new JsonException(
+ "Unexpected multi value array data found for
single-value restriction value for name: "
+ + restrictionName);
}
+ } else {
+ Value v = toValue(vf, jsonValue, restrictionType);
+ lr = new LocalRestriction(restrictionName, v);
}
}
+ if (lr != null) {
+ restrictions.add(lr);
+ }
}
-
- // do the work.
- if (restrictionsMap == null && mvRestrictionsMap == null &&
removedRestrictionNames == null) {
- contentCreator.createAce(principalID, grantedPrivileges,
deniedPrivileges, order);
- } else {
- contentCreator.createAce(principalID, grantedPrivileges,
deniedPrivileges, order, restrictionsMap,
- mvRestrictionsMap, removedRestrictionNames == null ? null
: removedRestrictionNames);
- }
+ return restrictions;
}
/**
diff --git
a/src/test/java/org/apache/sling/jcr/contentloader/ContentCreatorTest.java
b/src/test/java/org/apache/sling/jcr/contentloader/ContentCreatorTest.java
new file mode 100644
index 0000000..95427ab
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/contentloader/ContentCreatorTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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.contentloader;
+
+import java.io.InputStream;
+import java.util.Map;
+
+import javax.jcr.RepositoryException;
+
+import org.junit.Test;
+
+/**
+ * Tests to verify the ContentCreator default methods
+ * for an old impl that does not provide an implementation
+ * for those methods
+ */
+public class ContentCreatorTest {
+
+ private ContentCreator contentCreator = new ContentCreatorOldImpl();
+
+ @Test(expected = UnsupportedOperationException.class)
+ public void testCreateAce1() throws RepositoryException {
+ contentCreator.createAce(null, null, null);
+ }
+
+ @Deprecated
+ @Test(expected = UnsupportedOperationException.class)
+ public void testCreateAce2() throws RepositoryException{
+ contentCreator.createAce(null, null, null, null, null, null, null);
+ }
+
+ /**
+ * An impl that doesn't provide implementations for the default methods
+ */
+ protected static class ContentCreatorOldImpl implements ContentCreator {
+
+ @Override
+ public void createNode(String name, String primaryNodeType, String[]
mixinNodeTypes)
+ throws RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void finishNode() throws RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void finish() throws RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void createProperty(String name, int propertyType, String
value) throws RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void createProperty(String name, int propertyType, String[]
values) throws RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void createProperty(String name, Object value) throws
RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void createProperty(String name, Object[] values) throws
RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void createFileAndResourceNode(String name, InputStream data,
String mimeType, long lastModified)
+ throws RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public boolean switchCurrentNode(String subPath, String newNodeType)
throws RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void createUser(String name, String password, Map<String,
Object> extraProperties)
+ throws RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void createGroup(String name, String[] members, Map<String,
Object> extraProperties)
+ throws RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public void createAce(String principal, String[] grantedPrivileges,
String[] deniedPrivileges, String order)
+ throws RepositoryException {
+ throw new UnsupportedOperationException();
+ }
+
+ }
+
+}
diff --git
a/src/test/java/org/apache/sling/jcr/contentloader/LocalPrivilegeTest.java
b/src/test/java/org/apache/sling/jcr/contentloader/LocalPrivilegeTest.java
new file mode 100644
index 0000000..ac7a307
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/contentloader/LocalPrivilegeTest.java
@@ -0,0 +1,328 @@
+/*
+ * 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.contentloader;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Set;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.Value;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.Privilege;
+
+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.privilege.PrivilegeConstants;
+import org.apache.jackrabbit.value.ValueFactoryImpl;
+import org.apache.sling.jcr.base.util.AccessControlUtil;
+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 LocalPrivilegeTest {
+
+ @Rule
+ public final SlingContext context = new
SlingContext(ResourceResolverType.JCR_OAK);
+
+ private AccessControlManager acm;
+
+ @Before
+ public void setup() throws RepositoryException {
+ Session session = context.resourceResolver().adaptTo(Session.class);
+ acm = AccessControlUtil.getAccessControlManager(session);
+ context.registerService(new RestrictionProviderImpl());
+ }
+
+ private Privilege priv(String privilegeName) throws RepositoryException {
+ return acm.privilegeFromName(privilegeName);
+ }
+
+ private Value val(String value) {
+ return ValueFactoryImpl.getInstance().createValue(value);
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalPrivilege#hashCode()}.
+ */
+ @Test
+ public void testHashCode() {
+ LocalPrivilege lp1 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ LocalPrivilege lp2 = new LocalPrivilege(PrivilegeConstants.JCR_WRITE);
+ assertNotEquals(lp1.hashCode(), lp2.hashCode());
+
+ LocalPrivilege lp3 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ assertEquals(lp1.hashCode(), lp3.hashCode());
+
+ LocalPrivilege lp4 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp4.setAllow(true);
+ assertNotEquals(lp1.hashCode(), lp4.hashCode());
+ lp4.setDeny(true);
+ assertNotEquals(lp1.hashCode(), lp4.hashCode());
+ lp4.setAllowRestrictions(null);
+ assertNotEquals(lp1.hashCode(), lp4.hashCode());
+ lp4.setDenyRestrictions(null);
+ assertNotEquals(lp1.hashCode(), lp4.hashCode());
+
+ LocalPrivilege lp5 = new LocalPrivilege(null);
+ assertNotEquals(lp1.hashCode(), lp5.hashCode());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalPrivilege#checkPrivilege(javax.jcr.security.AccessControlManager)}.
+ * @throws RepositoryException
+ */
+ @Test
+ public void testCheckPrivilege() throws RepositoryException {
+ LocalPrivilege lp1 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp1.checkPrivilege(acm);
+ assertNotNull(lp1.getPrivilege());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalPrivilege#getPrivilege()}.
+ * @throws RepositoryException
+ */
+ @Test
+ public void testGetPrivilege() throws RepositoryException {
+ LocalPrivilege lp1 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp1.checkPrivilege(acm);
+ assertEquals(priv(PrivilegeConstants.JCR_READ), lp1.getPrivilege());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalPrivilege#getName()}.
+ */
+ @Test
+ public void testGetName() {
+ LocalPrivilege lp1 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ assertEquals(PrivilegeConstants.JCR_READ, lp1.getName());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalPrivilege#isAllow()}.
+ */
+ @Test
+ public void testIsAllow() {
+ LocalPrivilege lp1 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ assertFalse(lp1.isAllow());
+
+ lp1.setAllow(true);
+ assertTrue(lp1.isAllow());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalPrivilege#isDeny()}.
+ */
+ @Test
+ public void testIsDeny() {
+ LocalPrivilege lp1 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ assertFalse(lp1.isDeny());
+
+ lp1.setDeny(true);
+ assertTrue(lp1.isDeny());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalPrivilege#setAllow(boolean)}.
+ */
+ @Test
+ public void testSetAllow() {
+ LocalPrivilege lp1 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp1.setAllow(true);
+ assertTrue(lp1.isAllow());
+ lp1.setAllow(false);
+ assertFalse(lp1.isAllow());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalPrivilege#setDeny(boolean)}.
+ */
+ @Test
+ public void testSetDeny() {
+ LocalPrivilege lp1 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp1.setDeny(true);
+ assertTrue(lp1.isDeny());
+ lp1.setDeny(false);
+ assertFalse(lp1.isDeny());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalPrivilege#getAllowRestrictions()}.
+ */
+ @Test
+ public void testGetAllowRestrictions() {
+ LocalPrivilege lp1 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ Set<LocalRestriction> allowRestrictions = lp1.getAllowRestrictions();
+ assertNotNull(allowRestrictions);
+ assertTrue(allowRestrictions.isEmpty());
+
+ Set<LocalRestriction> newAllowRestrictions = new HashSet<>();
+ newAllowRestrictions.add(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello")));
+ lp1.setAllowRestrictions(newAllowRestrictions);
+ Set<LocalRestriction> allowRestrictions2 = lp1.getAllowRestrictions();
+ assertNotNull(allowRestrictions2);
+ assertFalse(allowRestrictions2.isEmpty());
+ assertEquals(newAllowRestrictions, allowRestrictions2);
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalPrivilege#setAllowRestrictions(java.util.Set)}.
+ */
+ @Test
+ public void testSetAllowRestrictions() {
+ LocalPrivilege lp1 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ assertTrue(lp1.getAllowRestrictions().isEmpty());
+
+ Set<LocalRestriction> newAllowRestrictions = new HashSet<>();
+ newAllowRestrictions.add(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello")));
+ lp1.setAllowRestrictions(newAllowRestrictions);
+ assertEquals(newAllowRestrictions, lp1.getAllowRestrictions());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalPrivilege#getDenyRestrictions()}.
+ */
+ @Test
+ public void testGetDenyRestrictions() {
+ LocalPrivilege lp1 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ Set<LocalRestriction> denyRestrictions = lp1.getDenyRestrictions();
+ assertNotNull(denyRestrictions);
+ assertTrue(denyRestrictions.isEmpty());
+
+ Set<LocalRestriction> newDenyRestrictions = new HashSet<>();
+ newDenyRestrictions.add(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello")));
+ lp1.setDenyRestrictions(newDenyRestrictions);
+ Set<LocalRestriction> denyRestrictions2 = lp1.getDenyRestrictions();
+ assertNotNull(denyRestrictions2);
+ assertFalse(denyRestrictions2.isEmpty());
+ assertEquals(newDenyRestrictions, denyRestrictions2);
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalPrivilege#setDenyRestrictions(java.util.Set)}.
+ */
+ @Test
+ public void testSetDenyRestrictions() {
+ LocalPrivilege lp1 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ assertTrue(lp1.getDenyRestrictions().isEmpty());
+
+ Set<LocalRestriction> newDenyRestrictions = new HashSet<>();
+ newDenyRestrictions.add(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello")));
+ lp1.setDenyRestrictions(newDenyRestrictions);
+ assertEquals(newDenyRestrictions, lp1.getDenyRestrictions());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalPrivilege#toString()}.
+ */
+ @Test
+ public void testToString() {
+ LocalPrivilege lp1 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ assertNotNull(lp1.toString());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalPrivilege#equals(java.lang.Object)}.
+ */
+ @Test
+ public void testEqualsObject() {
+ LocalPrivilege lp1 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ assertEquals(lp1, lp1);
+ assertNotEquals(lp1, null);
+ assertNotEquals(lp1, this);
+
+ LocalPrivilege lp2 = new LocalPrivilege(PrivilegeConstants.JCR_WRITE);
+ assertNotEquals(lp1, lp2);
+
+ LocalPrivilege lp3 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ assertEquals(lp1, lp3);
+
+ LocalPrivilege lp4 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp4.setAllow(true);
+ assertNotEquals(lp1, lp4);
+
+ LocalPrivilege lp5 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp5.setDeny(true);
+ assertNotEquals(lp1, lp5);
+
+ LocalPrivilege lp6 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp6.setAllowRestrictions(null);
+ assertNotEquals(lp1, lp6);
+
+ LocalPrivilege lp7 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp7.setDenyRestrictions(null);
+ assertNotEquals(lp1, lp7);
+
+ LocalPrivilege lp8 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp8.setAllowRestrictions(null);
+ LocalPrivilege lp9 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ assertNotEquals(lp8, lp9);
+
+ LocalPrivilege lp10 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp10.setDenyRestrictions(null);
+ LocalPrivilege lp11 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ assertNotEquals(lp10, lp11);
+
+ LocalPrivilege lp12 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp12.setAllowRestrictions(new HashSet<>(Arrays.asList(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello")))));
+ LocalPrivilege lp13 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ assertNotEquals(lp12, lp13);
+
+ LocalPrivilege lp14 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp14.setDenyRestrictions(new HashSet<>(Arrays.asList(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello")))));
+ LocalPrivilege lp15 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ assertNotEquals(lp14, lp15);
+
+ LocalPrivilege lp16 = new LocalPrivilege(null);
+ LocalPrivilege lp17 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ assertNotEquals(lp16, lp17);
+
+ LocalPrivilege lp18 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ LocalPrivilege lp19 = new LocalPrivilege(null);
+ assertNotEquals(lp18, lp19);
+
+ LocalPrivilege lp20 = new LocalPrivilege(null);
+ LocalPrivilege lp21 = new LocalPrivilege(null);
+ assertEquals(lp20, lp21);
+
+ LocalPrivilege lp22 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp22.setAllowRestrictions(null);
+ LocalPrivilege lp23 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp23.setAllowRestrictions(null);
+ assertEquals(lp22, lp23);
+
+ LocalPrivilege lp24 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp24.setDenyRestrictions(null);
+ LocalPrivilege lp25 = new LocalPrivilege(PrivilegeConstants.JCR_READ);
+ lp25.setDenyRestrictions(null);
+ assertEquals(lp24, lp25);
+ }
+
+}
diff --git
a/src/test/java/org/apache/sling/jcr/contentloader/LocalRestrictionTest.java
b/src/test/java/org/apache/sling/jcr/contentloader/LocalRestrictionTest.java
new file mode 100644
index 0000000..e3be41b
--- /dev/null
+++ b/src/test/java/org/apache/sling/jcr/contentloader/LocalRestrictionTest.java
@@ -0,0 +1,183 @@
+/*
+ * 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.contentloader;
+
+import static org.junit.Assert.assertArrayEquals;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNotSame;
+import static org.junit.Assert.assertNull;
+import static org.junit.Assert.assertTrue;
+
+import javax.jcr.PropertyType;
+import javax.jcr.Value;
+import javax.jcr.ValueFactory;
+import javax.jcr.ValueFormatException;
+
+import
org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
+import org.apache.jackrabbit.value.ValueFactoryImpl;
+import org.junit.Test;
+
+/**
+ *
+ */
+public class LocalRestrictionTest {
+
+ public static Value val(String value) throws ValueFormatException {
+ return val(ValueFactoryImpl.getInstance(), PropertyType.STRING, value);
+ }
+ public static Value val(ValueFactory vf, int type, String value) throws
ValueFormatException {
+ return vf.createValue(value, type);
+ }
+ public static Value[] vals(String ... value) throws ValueFormatException {
+ return vals(ValueFactoryImpl.getInstance(), PropertyType.STRING,
value);
+ }
+ public static Value[] vals(ValueFactory vf, int type, String ... value)
throws ValueFormatException {
+ Value[] values = new Value[value.length];
+ for (int i = 0; i < value.length; i++) {
+ values[i] = vf.createValue(value[i], type);
+ }
+ return values;
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalRestriction#hashCode()}.
+ */
+ @Test
+ public void testHashCode() throws ValueFormatException {
+ LocalRestriction lr1 = new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello1"));
+ LocalRestriction lr2 = new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello2"));
+ assertNotSame(lr1.hashCode(), lr2.hashCode());
+
+ LocalRestriction lr3 = new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello1"));
+ assertEquals(lr1.hashCode(), lr3.hashCode());
+
+ LocalRestriction lr4 = new LocalRestriction(null, (Value)null);
+ LocalRestriction lr5 = new LocalRestriction(null, (Value[])null);
+ assertNotSame(lr4.hashCode(), lr5.hashCode());
+ LocalRestriction lr6 = new LocalRestriction(null, (Value)null);
+ assertEquals(lr4.hashCode(), lr6.hashCode());
+ LocalRestriction lr7 = new LocalRestriction(null, (Value[])null);
+ assertEquals(lr5.hashCode(), lr7.hashCode());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalRestriction#getName()}.
+ */
+ @Test
+ public void testGetName() throws ValueFormatException {
+ LocalRestriction lr1 = new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello1"));
+ assertEquals(AccessControlConstants.REP_GLOB, lr1.getName());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalRestriction#isMultiValue()}.
+ */
+ @Test
+ public void testIsMultiValue() throws ValueFormatException {
+ LocalRestriction lr1 = new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello1"));
+ assertFalse(lr1.isMultiValue());
+
+ LocalRestriction lr2 = new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES, vals("item1", "item2"));
+ assertTrue(lr2.isMultiValue());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalRestriction#getValue()}.
+ */
+ @Test
+ public void testGetValue() throws ValueFormatException {
+ LocalRestriction lr1 = new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello1"));
+ assertEquals(val("/hello1"), lr1.getValue());
+
+ LocalRestriction lr2 = new
LocalRestriction(AccessControlConstants.REP_GLOB, (Value)null);
+ assertNull(lr2.getValue());
+
+ LocalRestriction lr3 = new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES, vals("item1", "item2"));
+ assertEquals(val("item1"), lr3.getValue());
+
+ LocalRestriction lr4 = new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES, (Value[])new Value[0]);
+ assertNull(lr4.getValue());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalRestriction#getValues()}.
+ */
+ @Test
+ public void testGetValues() throws ValueFormatException {
+ LocalRestriction lr1 = new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES, vals("item1", "item2"));
+ assertArrayEquals(vals("item1", "item2"), lr1.getValues());
+
+ LocalRestriction lr2 = new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES, (Value[])null);
+ assertNull(lr2.getValues());
+
+ LocalRestriction lr3 = new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES, new Value[0]);
+ assertArrayEquals(new Value[0], lr3.getValues());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalRestriction#toString()}.
+ */
+ @Test
+ public void testToString() throws ValueFormatException {
+ LocalRestriction lr1 = new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello1"));
+ assertNotNull(lr1.toString());
+
+ LocalRestriction lr2 = new LocalRestriction(null, val("/hello1"));
+ assertNotNull(lr2.toString());
+ }
+
+ /**
+ * Test method for {@link
org.apache.sling.jcr.contentloader.LocalRestriction#equals(java.lang.Object)}.
+ */
+ @Test
+ public void testEqualsObject() throws ValueFormatException {
+ LocalRestriction lr1 = new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello1"));
+ assertEquals(lr1, lr1);
+ assertNotEquals(lr1, null);
+ assertNotEquals(lr1, this);
+
+ LocalRestriction lr2 = new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello2"));
+ assertNotEquals(lr1, lr2);
+
+ LocalRestriction lr3 = new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello1"));
+ assertEquals(lr1, lr3);
+
+ LocalRestriction lr4 = new LocalRestriction(null, val("/hello1"));
+ LocalRestriction lr5 = new LocalRestriction(null, val("/hello1"));
+ assertEquals(lr4, lr5);
+
+ LocalRestriction lr6 = new LocalRestriction(null, val("/hello1"));
+ LocalRestriction lr7 = new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello1"));
+ assertNotEquals(lr6, lr7);
+
+ LocalRestriction lr8 = new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello1"));
+ LocalRestriction lr9 = new LocalRestriction(null, val("/hello1"));
+ assertNotEquals(lr8, lr9);
+
+ LocalRestriction lr10 = new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello1"));
+ LocalRestriction lr11 = new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES, vals("/hello1"));
+ assertNotEquals(lr10, lr11);
+
+ LocalRestriction lr12 = new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello1"));
+ LocalRestriction lr13 = new
LocalRestriction(AccessControlConstants.REP_GLOB, val("/hello2"));
+ assertNotEquals(lr12, lr13);
+ }
+
+}
diff --git
a/src/test/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreatorTest.java
b/src/test/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreatorTest.java
index c316a46..5ee76fc 100644
---
a/src/test/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreatorTest.java
+++
b/src/test/java/org/apache/sling/jcr/contentloader/internal/DefaultContentCreatorTest.java
@@ -22,29 +22,48 @@ import static
org.apache.sling.jcr.contentloader.ImportOptionsFactory.NO_OPTIONS
import static
org.apache.sling.jcr.contentloader.ImportOptionsFactory.OVERWRITE_NODE;
import static
org.apache.sling.jcr.contentloader.ImportOptionsFactory.OVERWRITE_PROPERTIES;
import static
org.apache.sling.jcr.contentloader.ImportOptionsFactory.createImportOptions;
+import static org.apache.sling.jcr.contentloader.LocalRestrictionTest.val;
+import static org.apache.sling.jcr.contentloader.LocalRestrictionTest.vals;
+import static
org.apache.sling.jcr.contentloader.it.SLING11713InitialContentIT.assertAce;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertThrows;
import static org.junit.Assert.assertTrue;
import java.text.ParseException;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Calendar;
+import java.util.Collections;
import java.util.Deque;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.UUID;
+import javax.jcr.AccessDeniedException;
import javax.jcr.Node;
+import javax.jcr.PathNotFoundException;
import javax.jcr.Property;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
+import javax.jcr.UnsupportedRepositoryOperationException;
+import javax.jcr.ValueFormatException;
import javax.jcr.nodetype.NodeType;
-
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+
+import
org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
+import org.apache.sling.jcr.base.util.AccessControlUtil;
import org.apache.sling.jcr.contentloader.ContentImportListener;
import org.apache.sling.jcr.contentloader.ContentReader;
+import org.apache.sling.jcr.contentloader.LocalPrivilege;
+import org.apache.sling.jcr.contentloader.LocalRestriction;
import org.apache.sling.testing.mock.sling.ResourceResolverType;
import org.apache.sling.testing.mock.sling.junit.SlingContext;
import org.jmock.Expectations;
@@ -547,6 +566,659 @@ public class DefaultContentCreatorTest {
assertFalse(parentNode.hasProperty(propName));
}
+ @Test
+ public void createAceWithoutRestrictionsSpecified() throws
RepositoryException {
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+ contentCreator.createUser(userName, "Test", null);
+
+ contentCreator.createAce(userName, new String[]
{PrivilegeConstants.JCR_READ},
+ new String[] {PrivilegeConstants.JCR_WRITE}, null);
+
+ contentCreator.finishNode();
+
+ //verify ACE was set.
+ List<AccessControlEntry> allEntries = allEntries();
+ assertEquals(2, allEntries.size());
+ assertAce(allEntries.get(0), userName,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {}, // RestrictionNames
+ new String[][] {}); // RestrictionValues
+ assertAce(allEntries.get(1), userName,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {}, // RestrictionNames
+ new String[][] {}); // RestrictionValues
+ }
+
+ @Deprecated
+ @Test
+ public void createAceWithNonSpecificRestrictions() throws
RepositoryException {
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+ contentCreator.createUser(userName, "Test", null);
+
+ contentCreator.createAce(userName, new String[]
{PrivilegeConstants.JCR_READ},
+ new String[] {PrivilegeConstants.JCR_WRITE}, null,
+ Collections.singletonMap(AccessControlConstants.REP_GLOB,
val("glob1allow")), // restrictions
+
Collections.singletonMap(AccessControlConstants.REP_ITEM_NAMES,
vals(session.getValueFactory(), PropertyType.NAME, "name1", "name2")), //
mvRestrictions
+ Collections.emptySet()); // removedRestrictionNames
+
+ contentCreator.finishNode();
+
+ //verify ACE was set.
+ List<AccessControlEntry> allEntries = allEntries();
+ assertEquals(2, allEntries.size());
+ assertAce(allEntries.get(0), userName,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_GLOB,
AccessControlConstants.REP_ITEM_NAMES}, // RestrictionNames
+ new String[][] {new String[]{"glob1allow"}, new String[]
{"name1", "name2"}}); // RestrictionValues
+ assertAce(allEntries.get(1), userName,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_GLOB,
AccessControlConstants.REP_ITEM_NAMES}, // RestrictionNames
+ new String[][] {new String[]{"glob1allow"}, new String[]
{"name1", "name2"}}); // RestrictionValues
+ }
+
+ @Deprecated
+ @Test
+ public void createAceWithNullSpecificRestrictions() throws
RepositoryException {
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+ contentCreator.createUser(userName, "Test", null);
+
+ contentCreator.createAce(userName, new String[]
{PrivilegeConstants.JCR_READ},
+ new String[] {PrivilegeConstants.JCR_WRITE}, null,
+ null, // restrictions
+ null, // mvRestrictions
+ null); // removedRestrictionNames
+
+ contentCreator.finishNode();
+
+ //verify ACE was set.
+ List<AccessControlEntry> allEntries = allEntries();
+ assertEquals(2, allEntries.size());
+ assertAce(allEntries.get(0), userName,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {}, // RestrictionNames
+ new String[][] {}); // RestrictionValues
+ assertAce(allEntries.get(1), userName,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {}, // RestrictionNames
+ new String[][] {}); // RestrictionValues
+ }
+
+ @Test
+ public void createAceWithSpecificRestrictions() throws RepositoryException
{
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+ contentCreator.createUser(userName, "Test", null);
+
+ List<LocalPrivilege> list = new ArrayList<>();
+ LocalPrivilege readLp = new
LocalPrivilege(PrivilegeConstants.JCR_READ);
+ readLp.setAllow(true);
+ readLp.setAllowRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("glob1allow"))));
+ list.add(readLp);
+ LocalPrivilege writeLp = new
LocalPrivilege(PrivilegeConstants.JCR_WRITE);
+ writeLp.setDeny(true);
+ writeLp.setDenyRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES,
vals(session.getValueFactory(), PropertyType.NAME, "name1", "name2"))));
+ list.add(writeLp);
+ contentCreator.createAce(userName, list, null);
+
+ contentCreator.finishNode();
+
+ //verify ACE was set.
+ List<AccessControlEntry> allEntries = allEntries();
+ assertEquals(2, allEntries.size());
+ assertAce(allEntries.get(0), userName,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_ITEM_NAMES}, //
RestrictionNames
+ new String[][] {new String[]{"name1", "name2"}}); //
RestrictionValues
+ assertAce(allEntries.get(1), userName,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_GLOB}, //
RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+ }
+
+ @Test
+ public void createAceWithSpecificRestrictionsTwice() throws
RepositoryException {
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+ contentCreator.createUser(userName, "Test", null);
+
+ List<LocalPrivilege> list = new ArrayList<>();
+ LocalPrivilege readLp = new
LocalPrivilege(PrivilegeConstants.JCR_READ);
+ readLp.setAllow(true);
+ readLp.setAllowRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("glob1allow"))));
+ list.add(readLp);
+ LocalPrivilege writeLp = new
LocalPrivilege(PrivilegeConstants.JCR_WRITE);
+ writeLp.setDeny(true);
+ writeLp.setDenyRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES,
vals(session.getValueFactory(), PropertyType.NAME, "name1", "name2"))));
+ list.add(writeLp);
+ contentCreator.createAce(userName, list, null);
+ // call again to verify the old aces are replaced with the new ones
+ contentCreator.createAce(userName, list, null);
+
+ contentCreator.finishNode();
+
+ //verify ACE was set.
+ List<AccessControlEntry> allEntries = allEntries();
+ assertEquals(2, allEntries.size());
+ assertAce(allEntries.get(0), userName,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_ITEM_NAMES}, //
RestrictionNames
+ new String[][] {new String[]{"name1", "name2"}}); //
RestrictionValues
+ assertAce(allEntries.get(1), userName,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_GLOB}, //
RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+ }
+
+ @Test
+ public void createAceWithNullPrivileges() throws RepositoryException {
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+ contentCreator.createUser(userName, "Test", null);
+
+ // try all null privilege args
+ contentCreator.createAce(userName, null, null, null);
+
+ contentCreator.finishNode();
+
+ //verify ACE was set.
+ List<AccessControlEntry> allEntries = allEntries();
+ assertEquals(0, allEntries.size());
+ }
+
+ @Test
+ public void createAceWithNullPrincipal() throws RepositoryException {
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+ contentCreator.createUser(userName, "Test", null);
+
+ // try null principal
+ assertThrows("No principal found for id: null",
RepositoryException.class, () -> {
+ contentCreator.createAce(null, new String[]
{PrivilegeConstants.JCR_READ},
+ new String[] {PrivilegeConstants.JCR_WRITE}, null);
+ });
+
+ contentCreator.finishNode();
+
+ //verify ACE was not set.
+ List<AccessControlEntry> allEntries = allEntries();
+ assertEquals(0, allEntries.size());
+ }
+
+ @Test
+ public void createAceWithInvalidPrincipal() throws RepositoryException {
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+
+ // try non-existing principal
+ assertThrows(String.format("No principal found for id: %s", userName),
RepositoryException.class, () -> {
+ contentCreator.createAce(userName, new String[]
{PrivilegeConstants.JCR_READ},
+ new String[] {PrivilegeConstants.JCR_WRITE}, null);
+ });
+
+ contentCreator.finishNode();
+
+ //verify ACE was set.
+ List<AccessControlEntry> allEntries = allEntries();
+ assertEquals(0, allEntries.size());
+ }
+
+ @Test
+ public void createAceWithOrderByNull() throws RepositoryException {
+ createAceWithOrderBy(null);
+ }
+
+ protected void createAceWithOrderBy(String orderBy) throws
RepositoryException, ValueFormatException,
+ UnsupportedRepositoryOperationException, PathNotFoundException,
AccessDeniedException {
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+ contentCreator.createUser(userName, "Test", null);
+
+ final String groupName = uniqueId();
+ contentCreator.createGroup(groupName, null, null);
+
+ List<LocalPrivilege> list = new ArrayList<>();
+ LocalPrivilege readLp = new
LocalPrivilege(PrivilegeConstants.JCR_READ);
+ readLp.setAllow(true);
+ readLp.setAllowRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("glob1allow"))));
+ list.add(readLp);
+ LocalPrivilege writeLp = new
LocalPrivilege(PrivilegeConstants.JCR_WRITE);
+ writeLp.setDeny(true);
+ writeLp.setDenyRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES,
vals(session.getValueFactory(), PropertyType.NAME, "name1", "name2"))));
+ list.add(writeLp);
+ contentCreator.createAce(userName, list, null);
+ contentCreator.createAce(groupName, list, orderBy);
+
+ contentCreator.finishNode();
+
+ //verify ACE was set.
+ List<AccessControlEntry> allEntries = allEntries();
+ assertEquals(4, allEntries.size());
+ assertAce(allEntries.get(0), userName,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_ITEM_NAMES}, //
RestrictionNames
+ new String[][] {new String[]{"name1", "name2"}}); //
RestrictionValues
+ assertAce(allEntries.get(1), userName,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_GLOB}, //
RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+ assertAce(allEntries.get(2), groupName,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_ITEM_NAMES}, //
RestrictionNames
+ new String[][] {new String[]{"name1", "name2"}}); //
RestrictionValues
+ assertAce(allEntries.get(3), groupName,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_GLOB}, //
RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+ }
+
+ @Test
+ public void createAceWithOrderByEmpty() throws RepositoryException {
+ createAceWithOrderBy("");
+ }
+
+ @Test
+ public void createAceWithOrderByFirst() throws RepositoryException {
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+ contentCreator.createUser(userName, "Test", null);
+
+ final String groupName = uniqueId();
+ contentCreator.createGroup(groupName, null, null);
+
+ List<LocalPrivilege> list = new ArrayList<>();
+ LocalPrivilege readLp = new
LocalPrivilege(PrivilegeConstants.JCR_READ);
+ readLp.setAllow(true);
+ readLp.setAllowRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("glob1allow"))));
+ list.add(readLp);
+ LocalPrivilege writeLp = new
LocalPrivilege(PrivilegeConstants.JCR_WRITE);
+ writeLp.setDeny(true);
+ writeLp.setDenyRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES,
vals(session.getValueFactory(), PropertyType.NAME, "name1", "name2"))));
+ list.add(writeLp);
+ contentCreator.createAce(userName, list, null);
+ contentCreator.createAce(groupName, list, "first");
+
+ contentCreator.finishNode();
+
+ //verify ACE was set.
+ List<AccessControlEntry> allEntries = allEntries();
+ assertEquals(4, allEntries.size());
+ assertAce(allEntries.get(0), groupName,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_ITEM_NAMES}, //
RestrictionNames
+ new String[][] {new String[]{"name1", "name2"}}); //
RestrictionValues
+ assertAce(allEntries.get(1), groupName,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_GLOB}, //
RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+ assertAce(allEntries.get(2), userName,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_ITEM_NAMES}, //
RestrictionNames
+ new String[][] {new String[]{"name1", "name2"}}); //
RestrictionValues
+ assertAce(allEntries.get(3), userName,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_GLOB}, //
RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+ }
+
+ @Test
+ public void createAceWithOrderByLast() throws RepositoryException {
+ createAceWithOrderBy("last");
+ }
+
+ @Test
+ public void createAceWithOrderByAfter() throws RepositoryException {
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+ contentCreator.createUser(userName, "Test", null);
+
+ final String userName2 = uniqueId();
+ contentCreator.createUser(userName2, "Test", null);
+
+ final String groupName = uniqueId();
+ contentCreator.createGroup(groupName, null, null);
+
+ List<LocalPrivilege> list = new ArrayList<>();
+ LocalPrivilege readLp = new
LocalPrivilege(PrivilegeConstants.JCR_READ);
+ readLp.setAllow(true);
+ readLp.setAllowRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("glob1allow"))));
+ list.add(readLp);
+ LocalPrivilege writeLp = new
LocalPrivilege(PrivilegeConstants.JCR_WRITE);
+ writeLp.setDeny(true);
+ writeLp.setDenyRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES,
vals(session.getValueFactory(), PropertyType.NAME, "name1", "name2"))));
+ list.add(writeLp);
+ contentCreator.createAce(userName, list, null);
+ contentCreator.createAce(userName2, list, null);
+ contentCreator.createAce(groupName, list, String.format("after %s",
userName));
+
+ contentCreator.finishNode();
+
+ //verify ACE was set.
+ List<AccessControlEntry> allEntries = allEntries();
+ assertEquals(6, allEntries.size());
+ assertAce(allEntries.get(0), userName,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_ITEM_NAMES}, //
RestrictionNames
+ new String[][] {new String[]{"name1", "name2"}}); //
RestrictionValues
+ assertAce(allEntries.get(1), userName,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_GLOB}, //
RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+ assertAce(allEntries.get(2), groupName,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_ITEM_NAMES}, //
RestrictionNames
+ new String[][] {new String[]{"name1", "name2"}}); //
RestrictionValues
+ assertAce(allEntries.get(3), groupName,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_GLOB}, //
RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+ assertAce(allEntries.get(4), userName2,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_ITEM_NAMES}, //
RestrictionNames
+ new String[][] {new String[]{"name1", "name2"}}); //
RestrictionValues
+ assertAce(allEntries.get(5), userName2,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_GLOB}, //
RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+ }
+
+ @Test
+ public void createAceWithOrderByBefore() throws RepositoryException {
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+ contentCreator.createUser(userName, "Test", null);
+
+ final String groupName = uniqueId();
+ contentCreator.createGroup(groupName, null, null);
+
+ List<LocalPrivilege> list = new ArrayList<>();
+ LocalPrivilege readLp = new
LocalPrivilege(PrivilegeConstants.JCR_READ);
+ readLp.setAllow(true);
+ readLp.setAllowRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("glob1allow"))));
+ list.add(readLp);
+ LocalPrivilege writeLp = new
LocalPrivilege(PrivilegeConstants.JCR_WRITE);
+ writeLp.setDeny(true);
+ writeLp.setDenyRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES,
vals(session.getValueFactory(), PropertyType.NAME, "name1", "name2"))));
+ list.add(writeLp);
+ contentCreator.createAce(userName, list, null);
+ contentCreator.createAce(groupName, list, String.format("before %s",
userName));
+
+ contentCreator.finishNode();
+
+ //verify ACE was set.
+ List<AccessControlEntry> allEntries = allEntries();
+ assertEquals(4, allEntries.size());
+ assertAce(allEntries.get(0), groupName,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_ITEM_NAMES}, //
RestrictionNames
+ new String[][] {new String[]{"name1", "name2"}}); //
RestrictionValues
+ assertAce(allEntries.get(1), groupName,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_GLOB}, //
RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+ assertAce(allEntries.get(2), userName,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_ITEM_NAMES}, //
RestrictionNames
+ new String[][] {new String[]{"name1", "name2"}}); //
RestrictionValues
+ assertAce(allEntries.get(3), userName,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_GLOB}, //
RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+ }
+
+ @Test
+ public void createAceWithOrderByAfterInvalid() throws RepositoryException {
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+ contentCreator.createUser(userName, "Test", null);
+
+ List<LocalPrivilege> list = new ArrayList<>();
+ LocalPrivilege readLp = new
LocalPrivilege(PrivilegeConstants.JCR_READ);
+ readLp.setAllow(true);
+ readLp.setAllowRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("glob1allow"))));
+ list.add(readLp);
+ LocalPrivilege writeLp = new
LocalPrivilege(PrivilegeConstants.JCR_WRITE);
+ writeLp.setDeny(true);
+ writeLp.setDenyRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES,
vals(session.getValueFactory(), PropertyType.NAME, "name1", "name2"))));
+ list.add(writeLp);
+ assertThrows("No ACE was found for the specified principal: invalid",
IllegalArgumentException.class, () -> {
+ contentCreator.createAce(userName, list, "after invalid");
+ });
+
+ contentCreator.finishNode();
+
+ //verify ACE was set.
+ List<AccessControlEntry> allEntries = allEntries();
+ assertEquals(0, allEntries.size());
+ }
+
+ @Test
+ public void createAceWithOrderByBeforeInvalid() throws RepositoryException
{
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+ contentCreator.createUser(userName, "Test", null);
+
+ List<LocalPrivilege> list = new ArrayList<>();
+ LocalPrivilege readLp = new
LocalPrivilege(PrivilegeConstants.JCR_READ);
+ readLp.setAllow(true);
+ readLp.setAllowRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("glob1allow"))));
+ list.add(readLp);
+ LocalPrivilege writeLp = new
LocalPrivilege(PrivilegeConstants.JCR_WRITE);
+ writeLp.setDeny(true);
+ writeLp.setDenyRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES,
vals(session.getValueFactory(), PropertyType.NAME, "name1", "name2"))));
+ list.add(writeLp);
+ assertThrows("No ACE was found for the specified principal: invalid",
IllegalArgumentException.class, () -> {
+ contentCreator.createAce(userName, list, "before invalid");
+ });
+
+ contentCreator.finishNode();
+
+ //verify ACE was set.
+ List<AccessControlEntry> allEntries = allEntries();
+ assertEquals(0, allEntries.size());
+ }
+
+ @Test
+ public void createAceWithOrderByIndex() throws RepositoryException {
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+ contentCreator.createUser(userName, "Test", null);
+
+ final String userName2 = uniqueId();
+ contentCreator.createUser(userName2, "Test", null);
+
+ final String groupName = uniqueId();
+ contentCreator.createGroup(groupName, null, null);
+
+ List<LocalPrivilege> list = new ArrayList<>();
+ LocalPrivilege readLp = new
LocalPrivilege(PrivilegeConstants.JCR_READ);
+ readLp.setAllow(true);
+ readLp.setAllowRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("glob1allow"))));
+ list.add(readLp);
+ LocalPrivilege writeLp = new
LocalPrivilege(PrivilegeConstants.JCR_WRITE);
+ writeLp.setDeny(true);
+ writeLp.setDenyRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES,
vals(session.getValueFactory(), PropertyType.NAME, "name1", "name2"))));
+ list.add(writeLp);
+ contentCreator.createAce(userName, list, null);
+ contentCreator.createAce(userName2, list, null);
+ contentCreator.createAce(groupName, list, "1");
+
+ contentCreator.finishNode();
+
+ //verify ACE was set.
+ List<AccessControlEntry> allEntries = allEntries();
+ assertEquals(6, allEntries.size());
+ assertAce(allEntries.get(0), userName,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_ITEM_NAMES}, //
RestrictionNames
+ new String[][] {new String[]{"name1", "name2"}}); //
RestrictionValues
+ assertAce(allEntries.get(1), userName,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_GLOB}, //
RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+ assertAce(allEntries.get(2), groupName,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_ITEM_NAMES}, //
RestrictionNames
+ new String[][] {new String[]{"name1", "name2"}}); //
RestrictionValues
+ assertAce(allEntries.get(3), groupName,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_GLOB}, //
RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+ assertAce(allEntries.get(4), userName2,
+ false, // isAllow
+ new String[] {PrivilegeConstants.JCR_WRITE}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_ITEM_NAMES}, //
RestrictionNames
+ new String[][] {new String[]{"name1", "name2"}}); //
RestrictionValues
+ assertAce(allEntries.get(5), userName2,
+ true, // isAllow
+ new String[] {PrivilegeConstants.JCR_READ}, // PrivilegeNames
+ new String[] {AccessControlConstants.REP_GLOB}, //
RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+ }
+
+ @Test
+ public void createAceWithOrderByInvalid() throws RepositoryException {
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+ contentCreator.createUser(userName, "Test", null);
+
+ List<LocalPrivilege> list = new ArrayList<>();
+ LocalPrivilege readLp = new
LocalPrivilege(PrivilegeConstants.JCR_READ);
+ readLp.setAllow(true);
+ readLp.setAllowRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("glob1allow"))));
+ list.add(readLp);
+ LocalPrivilege writeLp = new
LocalPrivilege(PrivilegeConstants.JCR_WRITE);
+ writeLp.setDeny(true);
+ writeLp.setDenyRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES,
vals(session.getValueFactory(), PropertyType.NAME, "name1", "name2"))));
+ list.add(writeLp);
+ assertThrows("Illegal value for the order parameter: invalid",
IllegalArgumentException.class, () -> {
+ contentCreator.createAce(userName, list, "invalid");
+ });
+
+ contentCreator.finishNode();
+ }
+
+ @Test
+ public void createAceWithOrderByIndexTooLarge() throws RepositoryException
{
+ contentCreator.init(createImportOptions(NO_OPTIONS),
+ new HashMap<String, ContentReader>(), null, null);
+ contentCreator.prepareParsing(parentNode, null);
+
+ final String userName = uniqueId();
+ contentCreator.createUser(userName, "Test", null);
+
+ List<LocalPrivilege> list = new ArrayList<>();
+ LocalPrivilege readLp = new
LocalPrivilege(PrivilegeConstants.JCR_READ);
+ readLp.setAllow(true);
+ readLp.setAllowRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_GLOB, val("glob1allow"))));
+ list.add(readLp);
+ LocalPrivilege writeLp = new
LocalPrivilege(PrivilegeConstants.JCR_WRITE);
+ writeLp.setDeny(true);
+ writeLp.setDenyRestrictions(Collections.singleton(new
LocalRestriction(AccessControlConstants.REP_ITEM_NAMES,
vals(session.getValueFactory(), PropertyType.NAME, "name1", "name2"))));
+ list.add(writeLp);
+ assertThrows("Index value is too large: 100",
IndexOutOfBoundsException.class, () -> {
+ contentCreator.createAce(userName, list, "100");
+ });
+
+ contentCreator.finishNode();
+ }
+
+ protected List<AccessControlEntry> allEntries() throws
UnsupportedRepositoryOperationException, RepositoryException,
+ PathNotFoundException, AccessDeniedException {
+ AccessControlManager accessControlManager =
AccessControlUtil.getAccessControlManager(session);
+ AccessControlPolicy[] policies =
accessControlManager.getPolicies(parentNode.getPath());
+ List<AccessControlEntry> allEntries = new
ArrayList<AccessControlEntry>();
+ for (AccessControlPolicy accessControlPolicy : policies) {
+ if (accessControlPolicy instanceof AccessControlList) {
+ AccessControlEntry[] accessControlEntries =
((AccessControlList) accessControlPolicy).getAccessControlEntries();
+ allEntries.addAll(Arrays.asList(accessControlEntries));
+ }
+ }
+ return allEntries;
+ }
+
private final String uniqueId() {
return getClass().getSimpleName() + UUID.randomUUID();
}
diff --git
a/src/test/java/org/apache/sling/jcr/contentloader/internal/JsonReaderTest.java
b/src/test/java/org/apache/sling/jcr/contentloader/internal/JsonReaderTest.java
index 3ee80ec..753ede8 100644
---
a/src/test/java/org/apache/sling/jcr/contentloader/internal/JsonReaderTest.java
+++
b/src/test/java/org/apache/sling/jcr/contentloader/internal/JsonReaderTest.java
@@ -20,7 +20,10 @@ import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.StringWriter;
+import java.util.ArrayList;
+import java.util.Collection;
import java.util.LinkedHashMap;
+import java.util.List;
import javax.jcr.PropertyType;
import javax.jcr.RepositoryException;
@@ -29,6 +32,7 @@ import jakarta.json.JsonArrayBuilder;
import jakarta.json.JsonWriter;
import org.apache.sling.jcr.contentloader.ContentCreator;
+import org.apache.sling.jcr.contentloader.LocalPrivilege;
import org.apache.sling.jcr.contentloader.internal.readers.JsonReader;
import org.jmock.Expectations;
import org.jmock.Sequence;
@@ -446,6 +450,19 @@ public class JsonReaderTest {
this.parse(json);
}
+ /**
+ * Return a collection that will pass the equals checking by mockit
+ * @param localPrivileges the privileges to make a collection
+ * @return collection of local privileges
+ */
+ private Collection<LocalPrivilege> toCollection(LocalPrivilege ...
localPrivileges) {
+ List<LocalPrivilege> list = new ArrayList<>();
+ for (LocalPrivilege lp: localPrivileges) {
+ list.add(lp);
+ }
+ return list;
+ }
+
@org.junit.Test
public void testCreateAcl() throws Exception {
String json = " { " + "\"security:acl\" : [ " + " { " + "
\"principal\" : \"username1\","
@@ -453,17 +470,25 @@ public class JsonReaderTest {
+ " \"principal\" : \"groupname1\"," + " \"granted\" :
[\"jcr:read\",\"jcr:write\"]" + " },"
+ " {" + " \"principal\" : \"groupname2\"," + "
\"granted\" : [\"jcr:read\"],"
+ " \"denied\" : [\"jcr:write\"]," + " \"order\" :
\"first\"" + " }" + "]" + "}";
+
+ LocalPrivilege readAllow = new LocalPrivilege("jcr:read");
+ readAllow.setAllow(true);
+ LocalPrivilege writeAllow = new LocalPrivilege("jcr:write");
+ writeAllow.setAllow(true);
+ LocalPrivilege writeDeny = new LocalPrivilege("jcr:write");
+ writeDeny.setDeny(true);
+
this.mockery.checking(new Expectations() {
{
allowing(creator).createNode(null, null, null);
inSequence(mySequence);
- allowing(creator).createAce("username1", new String[] {
"jcr:read", "jcr:write" }, new String[] {},
- null);
+ allowing(creator).getParent();
inSequence(mySequence);
- allowing(creator).createAce("groupname1", new String[] {
"jcr:read", "jcr:write" }, null, null);
+ allowing(creator).createAce("username1",
toCollection(readAllow, writeAllow), null);
inSequence(mySequence);
- allowing(creator).createAce("groupname2", new String[] {
"jcr:read" }, new String[] { "jcr:write" },
- "first");
+ allowing(creator).createAce("groupname1",
toCollection(readAllow, writeAllow), null);
+ inSequence(mySequence);
+ allowing(creator).createAce("groupname2",
toCollection(readAllow, writeDeny), "first");
inSequence(mySequence);
allowing(creator).finishNode();
inSequence(mySequence);
@@ -481,17 +506,25 @@ public class JsonReaderTest {
+ " 'principal' : 'groupname1'," + " 'granted' :
['jcr:read','jcr:write']" + " }," + " {"
+ " 'principal' : \"\\\"'groupname2'\"," + " 'granted' :
['jcr:read'],"
+ " 'denied' : ['jcr:write']," + " 'order' : 'first'" +
" }" + "]" + "}";
+
+ LocalPrivilege readAllow = new LocalPrivilege("jcr:read");
+ readAllow.setAllow(true);
+ LocalPrivilege writeAllow = new LocalPrivilege("jcr:write");
+ writeAllow.setAllow(true);
+ LocalPrivilege writeDeny = new LocalPrivilege("jcr:write");
+ writeDeny.setDeny(true);
+
this.mockery.checking(new Expectations() {
{
allowing(creator).createNode(null, null, null);
inSequence(mySequence);
- allowing(creator).createAce("username1", new String[] {
"jcr:read", "jcr:write" }, new String[] {},
- null);
+ allowing(creator).getParent();
+ inSequence(mySequence);
+ allowing(creator).createAce("username1",
toCollection(readAllow, writeAllow), null);
inSequence(mySequence);
- allowing(creator).createAce("groupname1", new String[] {
"jcr:read", "jcr:write" }, null, null);
+ allowing(creator).createAce("groupname1",
toCollection(readAllow, writeAllow), null);
inSequence(mySequence);
- allowing(creator).createAce("\"'groupname2'", new String[] {
"jcr:read" }, new String[] { "jcr:write" },
- "first");
+ allowing(creator).createAce("\"'groupname2'",
toCollection(readAllow, writeDeny), "first");
inSequence(mySequence);
allowing(creator).finishNode();
inSequence(mySequence);
diff --git
a/src/test/java/org/apache/sling/jcr/contentloader/it/ContentloaderTestSupport.java
b/src/test/java/org/apache/sling/jcr/contentloader/it/ContentloaderTestSupport.java
index 6a3bee2..c635514 100644
---
a/src/test/java/org/apache/sling/jcr/contentloader/it/ContentloaderTestSupport.java
+++
b/src/test/java/org/apache/sling/jcr/contentloader/it/ContentloaderTestSupport.java
@@ -29,6 +29,7 @@ import static org.ops4j.pax.exam.CoreOptions.composite;
import static org.ops4j.pax.exam.CoreOptions.junitBundles;
import static org.ops4j.pax.exam.CoreOptions.mavenBundle;
import static org.ops4j.pax.exam.CoreOptions.streamBundle;
+import static org.ops4j.pax.exam.CoreOptions.when;
import static
org.ops4j.pax.exam.cm.ConfigurationAdminOptions.factoryConfiguration;
import static org.ops4j.pax.tinybundles.core.TinyBundles.withBnd;
@@ -59,6 +60,7 @@ import org.junit.After;
import org.junit.Before;
import org.ops4j.pax.exam.Option;
import org.ops4j.pax.exam.options.ModifiableCompositeOption;
+import org.ops4j.pax.exam.options.extra.VMOption;
import org.ops4j.pax.exam.util.Filter;
import org.ops4j.pax.tinybundles.core.TinyBundle;
import org.ops4j.pax.tinybundles.core.TinyBundles;
@@ -106,9 +108,23 @@ public abstract class ContentloaderTestSupport extends
TestSupport {
private HealthCheckExecutor hcExecutor;
public ModifiableCompositeOption baseConfiguration() {
+ final String vmOpt = System.getProperty("pax.vm.options");
+ VMOption vmOption = null;
+ if (vmOpt != null && !vmOpt.isEmpty()) {
+ vmOption = new VMOption(vmOpt);
+ }
+
+ final String jacocoOpt = System.getProperty("jacoco.command");
+ VMOption jacocoCommand = null;
+ if (jacocoOpt != null && !jacocoOpt.isEmpty()) {
+ jacocoCommand = new VMOption(jacocoOpt);
+ }
+
final Option contentloader =
mavenBundle().groupId("org.apache.sling").artifactId("org.apache.sling.jcr.contentloader").version(SlingOptions.versionResolver.getVersion("org.apache.sling",
"org.apache.sling.jcr.contentloader"));
return composite(
super.baseConfiguration(),
+ when(vmOption != null).useOptions(vmOption),
+ when(jacocoCommand != null).useOptions(jacocoCommand),
mavenBundle().groupId("org.glassfish").artifactId("jakarta.json").version("2.0.1"),
quickstart(),
// SLING-9735 - add server user for the o.a.s.jcr.contentloader
bundle
diff --git
a/src/test/java/org/apache/sling/jcr/contentloader/it/SLING11713InitialContentIT.java
b/src/test/java/org/apache/sling/jcr/contentloader/it/SLING11713InitialContentIT.java
new file mode 100644
index 0000000..119085c
--- /dev/null
+++
b/src/test/java/org/apache/sling/jcr/contentloader/it/SLING11713InitialContentIT.java
@@ -0,0 +1,289 @@
+/*
+ * 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.contentloader.it;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertTrue;
+import static org.ops4j.pax.exam.CoreOptions.composite;
+import static org.ops4j.pax.exam.CoreOptions.vmOption;
+import static
org.ops4j.pax.exam.cm.ConfigurationAdminOptions.factoryConfiguration;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Value;
+import javax.jcr.security.AccessControlEntry;
+import javax.jcr.security.AccessControlList;
+import javax.jcr.security.AccessControlManager;
+import javax.jcr.security.AccessControlPolicy;
+import javax.jcr.security.Privilege;
+
+import org.apache.jackrabbit.api.security.JackrabbitAccessControlEntry;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.Group;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.sling.jcr.base.util.AccessControlUtil;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.ops4j.pax.exam.Configuration;
+import org.ops4j.pax.exam.Option;
+import org.ops4j.pax.exam.junit.PaxExam;
+import org.ops4j.pax.exam.options.ModifiableCompositeOption;
+import org.ops4j.pax.exam.options.extra.VMOption;
+import org.ops4j.pax.exam.spi.reactors.ExamReactorStrategy;
+import org.ops4j.pax.exam.spi.reactors.PerClass;
+import org.osgi.framework.Bundle;
+
+import com.google.common.collect.ImmutableListMultimap;
+import com.google.common.collect.Multimap;
+
+/**
+ * SLING-11713 test ACL json input structure to be less ambiguous for
restrictions
+ */
+@RunWith(PaxExam.class)
+@ExamReactorStrategy(PerClass.class)
+public class SLING11713InitialContentIT extends ContentloaderTestSupport {
+
+ @Configuration
+ public Option[] configuration() throws IOException {
+ final String header = DEFAULT_PATH_IN_BUNDLE + ";path:=" +
CONTENT_ROOT_PATH;
+ final Multimap<String, String> content = ImmutableListMultimap.of(
+ DEFAULT_PATH_IN_BUNDLE, "SLING-11713.json"
+ );
+ final Option bundle = buildInitialContentBundle(header, content);
+ // configure the health check component
+ Option hcConfig =
factoryConfiguration("org.apache.sling.jcr.contentloader.hc.BundleContentLoadedCheck")
+ .put("hc.tags", new String[] {TAG_TESTING_CONTENT_LOADING})
+ .asOption();
+ return new Option[]{
+ baseConfiguration(),
+ hcConfig,
+ bundle,
+ optionalRemoteDebug()
+ };
+ }
+
+ /**
+ * Optionally configure remote debugging on the port supplied by the
"debugPort"
+ * system property.
+ */
+ protected ModifiableCompositeOption optionalRemoteDebug() {
+ VMOption option = null;
+ String property = System.getProperty("debugPort");
+ if (property != null) {
+ option =
vmOption(String.format("-Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=%s",
property));
+ }
+ return composite(option);
+ }
+
+ /* (non-Javadoc)
+ * @see
org.apache.sling.jcr.contentloader.it.ContentloaderTestSupport#setup()
+ */
+ @Before
+ @Override
+ public void setup() throws Exception {
+ super.setup();
+
+ waitForContentLoaded();
+ }
+
+ @Test
+ public void bundleStarted() {
+ final Bundle b = findBundle(BUNDLE_SYMBOLICNAME);
+ assertNotNull("Expecting bundle to be found:" + BUNDLE_SYMBOLICNAME,
b);
+ assertEquals("Expecting bundle to be active:" + BUNDLE_SYMBOLICNAME,
Bundle.ACTIVE, b.getState());
+ }
+
+ @Test
+ public void initialContentInstalled() throws RepositoryException {
+ final String folderPath = CONTENT_ROOT_PATH + "/SLING-11713";
+ assertTrue("Expecting initial content to be installed",
session.itemExists(folderPath));
+ assertEquals("folder has node type 'sling:Folder'", "sling:Folder",
session.getNode(folderPath).getPrimaryNodeType().getName());
+ }
+
+ @Test
+ public void userCreated() throws RepositoryException {
+ UserManager userManager = AccessControlUtil.getUserManager(session);
+ Authorizable authorizable =
userManager.getAuthorizable("sling11713_user");
+ assertNotNull("Expecting test user to exist", authorizable);
+ }
+
+ @Test
+ public void groupCreated() throws RepositoryException {
+ UserManager userManager = AccessControlUtil.getUserManager(session);
+ Authorizable authorizable =
userManager.getAuthorizable("sling11713_group");
+ assertNotNull("Expecting test group to exist", authorizable);
+ assertTrue(authorizable instanceof Group);
+ Iterator<Authorizable> members = ((Group) authorizable).getMembers();
+ assertTrue(members.hasNext());
+ Authorizable firstMember = members.next();
+ assertEquals("sling11713_user", firstMember.getID());
+ }
+
+ @Test
+ public void aceWithRestrictionsCreated() throws RepositoryException {
+ final String folderPath = CONTENT_ROOT_PATH + "/SLING-11713";
+ assertTrue("Expecting test folder to exist",
session.itemExists(folderPath));
+
+ AccessControlManager accessControlManager =
AccessControlUtil.getAccessControlManager(session);
+ AccessControlPolicy[] policies =
accessControlManager.getPolicies(folderPath);
+ List<AccessControlEntry> allEntries = new
ArrayList<AccessControlEntry>();
+ for (AccessControlPolicy accessControlPolicy : policies) {
+ if (accessControlPolicy instanceof AccessControlList) {
+ AccessControlEntry[] accessControlEntries =
((AccessControlList) accessControlPolicy).getAccessControlEntries();
+ allEntries.addAll(Arrays.asList(accessControlEntries));
+ }
+ }
+ assertEquals(9, allEntries.size());
+ Map<String, List<AccessControlEntry>> aceMap = new HashMap<>();
+ for (AccessControlEntry accessControlEntry : allEntries) {
+ List<AccessControlEntry> aceList =
aceMap.computeIfAbsent(accessControlEntry.getPrincipal().getName(), name -> new
ArrayList<>());
+ aceList.add(accessControlEntry);
+ }
+
+ //check ACE for sling11713_user
+ List<AccessControlEntry> aceList = aceMap.get("sling11713_user");
+ assertNotNull(aceList);
+ assertEquals(3, aceList.size());
+ assertAce(aceList.get(0), "sling11713_user",
+ false, // isAllow
+ new String[] {"jcr:write"}, // PrivilegeNames
+ new String[] {"rep:glob"}, // RestrictionNames
+ new String[][] {new String[]{"glob1deny"}}); //
RestrictionValues
+ assertAce(aceList.get(1), "sling11713_user",
+ true, // isAllow
+ new String[] {"jcr:read"}, // PrivilegeNames
+ new String[] {}, // RestrictionNames
+ new String[][] {}); // RestrictionValues
+ assertAce(aceList.get(2), "sling11713_user",
+ true, // isAllow
+ new String[] {"jcr:write"}, // PrivilegeNames
+ new String[] {"rep:glob"}, // RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+
+ //check ACE for sling11713_group
+ aceList = aceMap.get("sling11713_group");
+ assertNotNull(aceList);
+ assertEquals(1, aceList.size());
+ assertAce(aceList.get(0), "sling11713_group",
+ true, // isAllow
+ new String[] {"jcr:modifyAccessControl"}, // PrivilegeNames
+ new String[] {"rep:itemNames"}, // RestrictionNames
+ new String[][] {new String[]{"name1", "name2"}}); //
RestrictionValues
+
+ //check ACE for everyone
+ aceList = aceMap.get("everyone");
+ assertNotNull(aceList);
+ assertEquals(3, aceList.size());
+ assertAce(aceList.get(0), "everyone",
+ false, // isAllow
+ new String[] {"jcr:write"}, // PrivilegeNames
+ new String[] {"rep:glob"}, // RestrictionNames
+ new String[][] {new String[]{"glob1deny"}}); //
RestrictionValues
+ assertAce(aceList.get(1), "everyone",
+ true, // isAllow
+ new String[] {"jcr:read"}, // PrivilegeNames
+ new String[] {}, // RestrictionNames
+ new String[][] {}); // RestrictionValues
+ assertAce(aceList.get(2), "everyone",
+ true, // isAllow
+ new String[] {"jcr:write"}, // PrivilegeNames
+ new String[] {"rep:glob"}, // RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+
+ aceList = aceMap.get("sling11713_user2");
+ assertNotNull(aceList);
+ assertEquals(2, aceList.size());
+ assertAce(aceList.get(0), "sling11713_user2",
+ false, // isAllow
+ new String[] {"jcr:read"}, // PrivilegeNames
+ new String[] {"rep:itemNames"}, // RestrictionNames
+ new String[][] {new String[]{"name1"}}); // RestrictionValues
+ assertAce(aceList.get(1), "sling11713_user2",
+ true, // isAllow
+ new String[] {"jcr:read"}, // PrivilegeNames
+ new String[] {"rep:glob"}, // RestrictionNames
+ new String[][] {new String[]{"glob1allow"}}); //
RestrictionValues
+ }
+
+ public static void assertAce(AccessControlEntry ace, String
expectedPrincipal,
+ boolean isAllow, String[] expectedPrivilegeNames,
+ String[] expectedRestrictionNames, String[][]
expectedRestrictionValues) throws RepositoryException {
+
+ assertNotNull("Expected ACE for test principal", expectedPrincipal);
+ assertEquals(expectedPrincipal, ace.getPrincipal().getName());
+
+ Privilege[] storedPrivileges = ace.getPrivileges();
+ assertNotNull(storedPrivileges);
+ assertEquals(expectedPrivilegeNames.length, storedPrivileges.length);
+ Set<String> privilegeNamesSet = Stream.of(storedPrivileges)
+ .map(item -> item.getName())
+ .collect(Collectors.toSet());
+ for (String pn : expectedPrivilegeNames) {
+ assertTrue("Expecting privilege: " + pn,
privilegeNamesSet.contains(pn));
+ }
+
+ assertTrue(ace instanceof JackrabbitAccessControlEntry);
+ JackrabbitAccessControlEntry jace = (JackrabbitAccessControlEntry) ace;
+ assertEquals(isAllow, jace.isAllow());
+
+ //check restrictions
+ String[] storedRestrictionNames = jace.getRestrictionNames();
+ assertNotNull(storedRestrictionNames);
+ assertEquals(expectedRestrictionNames.length,
storedRestrictionNames.length);
+ Set<String> restrictionNamesSet = Stream.of(storedRestrictionNames)
+ .collect(Collectors.toSet());
+ for (String rn : expectedRestrictionNames) {
+ assertTrue("Expecting restriction: " + rn,
restrictionNamesSet.contains(rn));
+ }
+
+ if (expectedRestrictionValues.length > 0) {
+ for (int i = 0; i < expectedRestrictionValues.length; i++) {
+ String[] expected = expectedRestrictionValues[i];
+ Value[] storedRestrictionValues =
jace.getRestrictions(storedRestrictionNames[i]);
+ assertNotNull(storedRestrictionValues);
+ assertEquals(expected.length, storedRestrictionValues.length);
+ Set<String> restrictionValuesSet =
Stream.of(storedRestrictionValues)
+ .map(item -> {
+ try {
+ return item.getString();
+ } catch (IllegalStateException |
RepositoryException e) {
+ // should never get here
+ return null;
+ }
+ })
+ .collect(Collectors.toSet());
+ for (String rv : expected) {
+ assertTrue("Expecting restriction value: " + rv,
restrictionValuesSet.contains(rv));
+ }
+ }
+ }
+ }
+}
diff --git a/src/test/resources/initial-content/SLING-11713.json
b/src/test/resources/initial-content/SLING-11713.json
new file mode 100644
index 0000000..367f2f7
--- /dev/null
+++ b/src/test/resources/initial-content/SLING-11713.json
@@ -0,0 +1,80 @@
+{
+ "jcr:primaryType" : "sling:Folder",
+ "security:principals": [
+ {
+ "name": "sling11713_user",
+ "password": "mypassword"
+ },
+ {
+ "name": "sling11713_group",
+ "isgroup": true,
+ "members":[
+ "sling11713_user"
+ ]
+ },
+ {
+ "name": "sling11713_user2",
+ "password": "mypassword"
+ }
+ ],
+ "security:acl": [
+ {
+ "principal": "everyone",
+ "granted": [
+ "jcr:read"
+ ],
+ "privileges":{
+ "jcr:write":{
+ "allow":{
+ "rep:glob":"glob1allow"
+ },
+ "deny":{
+ "rep:glob":"glob1deny"
+ }
+ }
+ }
+ },
+ {
+ "principal": "sling11713_user",
+ "privileges":{
+ "jcr:read": {
+ "allow": true
+ },
+ "jcr:write":{
+ "allow":{
+ "rep:glob":"glob1allow"
+ },
+ "deny":{
+ "rep:glob":"glob1deny"
+ }
+ }
+ }
+ },
+ {
+ "principal": "sling11713_group",
+ "privileges":{
+ "jcr:modifyAccessControl":{
+ "allow": {
+ "rep:itemNames": [
+ "name1",
+ "name2"
+ ]
+ }
+ }
+ }
+ },
+ {
+ "principal": "sling11713_user2",
+ "privileges":{
+ "jcr:read":{
+ "allow":{
+ "rep:glob":["glob1allow"]
+ },
+ "deny":{
+ "rep:itemNames": "name1"
+ }
+ }
+ }
+ }
+ ]
+}