You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@sling.apache.org by ro...@apache.org on 2017/11/07 09:47:29 UTC
[sling-org-apache-sling-jcr-jackrabbit-accessmanager] 02/16:
SLING-879: New Bundle to provide actions for interacting with the
jackrabbit AccessManager. Patch provided by Eric Norman.
https://issues.apache.org/jira/browse/SLING-879
This is an automated email from the ASF dual-hosted git repository.
rombert pushed a commit to annotated tag org.apache.sling.jcr.jackrabbit.accessmanager-2.0.2-incubator
in repository https://gitbox.apache.org/repos/asf/sling-org-apache-sling-jcr-jackrabbit-accessmanager.git
commit 6e7aae9a064dc9670e7bfcbee74a1de4bdd35056
Author: Juan Vazquez <jv...@apache.org>
AuthorDate: Wed Mar 18 14:56:31 2009 +0000
SLING-879: New Bundle to provide actions for interacting with the jackrabbit AccessManager. Patch provided by Eric Norman.
https://issues.apache.org/jira/browse/SLING-879
git-svn-id: https://svn.apache.org/repos/asf/incubator/sling/trunk/bundles/jcr/jackrabbit-accessmanager@755609 13f79535-47bb-0310-9956-ffa450edef68
---
LICENSE | 202 +++++++
NOTICE | 8 +
README.txt | 37 ++
pom.xml | 119 ++++
.../jackrabbit/accessmanager/PrivilegesInfo.java | 616 +++++++++++++++++++++
.../post/AbstractAccessPostServlet.java | 254 +++++++++
.../accessmanager/post/DeleteAcesServlet.java | 128 +++++
.../accessmanager/post/GetAclServlet.java | 180 ++++++
.../accessmanager/post/ModifyAceServlet.java | 241 ++++++++
.../OSGI-INF/metatype/metatype.properties | 25 +
.../accessmanager/PrivilegesResources.properties | 23 +
11 files changed, 1833 insertions(+)
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 0000000..75b5248
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,202 @@
+
+ Apache License
+ Version 2.0, January 2004
+ http://www.apache.org/licenses/
+
+ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
+
+ 1. Definitions.
+
+ "License" shall mean the terms and conditions for use, reproduction,
+ and distribution as defined by Sections 1 through 9 of this document.
+
+ "Licensor" shall mean the copyright owner or entity authorized by
+ the copyright owner that is granting the License.
+
+ "Legal Entity" shall mean the union of the acting entity and all
+ other entities that control, are controlled by, or are under common
+ control with that entity. For the purposes of this definition,
+ "control" means (i) the power, direct or indirect, to cause the
+ direction or management of such entity, whether by contract or
+ otherwise, or (ii) ownership of fifty percent (50%) or more of the
+ outstanding shares, or (iii) beneficial ownership of such entity.
+
+ "You" (or "Your") shall mean an individual or Legal Entity
+ exercising permissions granted by this License.
+
+ "Source" form shall mean the preferred form for making modifications,
+ including but not limited to software source code, documentation
+ source, and configuration files.
+
+ "Object" form shall mean any form resulting from mechanical
+ transformation or translation of a Source form, including but
+ not limited to compiled object code, generated documentation,
+ and conversions to other media types.
+
+ "Work" shall mean the work of authorship, whether in Source or
+ Object form, made available under the License, as indicated by a
+ copyright notice that is included in or attached to the work
+ (an example is provided in the Appendix below).
+
+ "Derivative Works" shall mean any work, whether in Source or Object
+ form, that is based on (or derived from) the Work and for which the
+ editorial revisions, annotations, elaborations, or other modifications
+ represent, as a whole, an original work of authorship. For the purposes
+ of this License, Derivative Works shall not include works that remain
+ separable from, or merely link (or bind by name) to the interfaces of,
+ the Work and Derivative Works thereof.
+
+ "Contribution" shall mean any work of authorship, including
+ the original version of the Work and any modifications or additions
+ to that Work or Derivative Works thereof, that is intentionally
+ submitted to Licensor for inclusion in the Work by the copyright owner
+ or by an individual or Legal Entity authorized to submit on behalf of
+ the copyright owner. For the purposes of this definition, "submitted"
+ means any form of electronic, verbal, or written communication sent
+ to the Licensor or its representatives, including but not limited to
+ communication on electronic mailing lists, source code control systems,
+ and issue tracking systems that are managed by, or on behalf of, the
+ Licensor for the purpose of discussing and improving the Work, but
+ excluding communication that is conspicuously marked or otherwise
+ designated in writing by the copyright owner as "Not a Contribution."
+
+ "Contributor" shall mean Licensor and any individual or Legal Entity
+ on behalf of whom a Contribution has been received by Licensor and
+ subsequently incorporated within the Work.
+
+ 2. Grant of Copyright License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ copyright license to reproduce, prepare Derivative Works of,
+ publicly display, publicly perform, sublicense, and distribute the
+ Work and such Derivative Works in Source or Object form.
+
+ 3. Grant of Patent License. Subject to the terms and conditions of
+ this License, each Contributor hereby grants to You a perpetual,
+ worldwide, non-exclusive, no-charge, royalty-free, irrevocable
+ (except as stated in this section) patent license to make, have made,
+ use, offer to sell, sell, import, and otherwise transfer the Work,
+ where such license applies only to those patent claims licensable
+ by such Contributor that are necessarily infringed by their
+ Contribution(s) alone or by combination of their Contribution(s)
+ with the Work to which such Contribution(s) was submitted. If You
+ institute patent litigation against any entity (including a
+ cross-claim or counterclaim in a lawsuit) alleging that the Work
+ or a Contribution incorporated within the Work constitutes direct
+ or contributory patent infringement, then any patent licenses
+ granted to You under this License for that Work shall terminate
+ as of the date such litigation is filed.
+
+ 4. Redistribution. You may reproduce and distribute copies of the
+ Work or Derivative Works thereof in any medium, with or without
+ modifications, and in Source or Object form, provided that You
+ meet the following conditions:
+
+ (a) You must give any other recipients of the Work or
+ Derivative Works a copy of this License; and
+
+ (b) You must cause any modified files to carry prominent notices
+ stating that You changed the files; and
+
+ (c) You must retain, in the Source form of any Derivative Works
+ that You distribute, all copyright, patent, trademark, and
+ attribution notices from the Source form of the Work,
+ excluding those notices that do not pertain to any part of
+ the Derivative Works; and
+
+ (d) If the Work includes a "NOTICE" text file as part of its
+ distribution, then any Derivative Works that You distribute must
+ include a readable copy of the attribution notices contained
+ within such NOTICE file, excluding those notices that do not
+ pertain to any part of the Derivative Works, in at least one
+ of the following places: within a NOTICE text file distributed
+ as part of the Derivative Works; within the Source form or
+ documentation, if provided along with the Derivative Works; or,
+ within a display generated by the Derivative Works, if and
+ wherever such third-party notices normally appear. The contents
+ of the NOTICE file are for informational purposes only and
+ do not modify the License. You may add Your own attribution
+ notices within Derivative Works that You distribute, alongside
+ or as an addendum to the NOTICE text from the Work, provided
+ that such additional attribution notices cannot be construed
+ as modifying the License.
+
+ You may add Your own copyright statement to Your modifications and
+ may provide additional or different license terms and conditions
+ for use, reproduction, or distribution of Your modifications, or
+ for any such Derivative Works as a whole, provided Your use,
+ reproduction, and distribution of the Work otherwise complies with
+ the conditions stated in this License.
+
+ 5. Submission of Contributions. Unless You explicitly state otherwise,
+ any Contribution intentionally submitted for inclusion in the Work
+ by You to the Licensor shall be under the terms and conditions of
+ this License, without any additional terms or conditions.
+ Notwithstanding the above, nothing herein shall supersede or modify
+ the terms of any separate license agreement you may have executed
+ with Licensor regarding such Contributions.
+
+ 6. Trademarks. This License does not grant permission to use the trade
+ names, trademarks, service marks, or product names of the Licensor,
+ except as required for reasonable and customary use in describing the
+ origin of the Work and reproducing the content of the NOTICE file.
+
+ 7. Disclaimer of Warranty. Unless required by applicable law or
+ agreed to in writing, Licensor provides the Work (and each
+ Contributor provides its Contributions) on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ implied, including, without limitation, any warranties or conditions
+ of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
+ PARTICULAR PURPOSE. You are solely responsible for determining the
+ appropriateness of using or redistributing the Work and assume any
+ risks associated with Your exercise of permissions under this License.
+
+ 8. Limitation of Liability. In no event and under no legal theory,
+ whether in tort (including negligence), contract, or otherwise,
+ unless required by applicable law (such as deliberate and grossly
+ negligent acts) or agreed to in writing, shall any Contributor be
+ liable to You for damages, including any direct, indirect, special,
+ incidental, or consequential damages of any character arising as a
+ result of this License or out of the use or inability to use the
+ Work (including but not limited to damages for loss of goodwill,
+ work stoppage, computer failure or malfunction, or any and all
+ other commercial damages or losses), even if such Contributor
+ has been advised of the possibility of such damages.
+
+ 9. Accepting Warranty or Additional Liability. While redistributing
+ the Work or Derivative Works thereof, You may choose to offer,
+ and charge a fee for, acceptance of support, warranty, indemnity,
+ or other liability obligations and/or rights consistent with this
+ License. However, in accepting such obligations, You may act only
+ on Your own behalf and on Your sole responsibility, not on behalf
+ of any other Contributor, and only if You agree to indemnify,
+ defend, and hold each Contributor harmless for any liability
+ incurred by, or claims asserted against, such Contributor by reason
+ of your accepting any such warranty or additional liability.
+
+ END OF TERMS AND CONDITIONS
+
+ APPENDIX: How to apply the Apache License to your work.
+
+ To apply the Apache License to your work, attach the following
+ boilerplate notice, with the fields enclosed by brackets "[]"
+ replaced with your own identifying information. (Don't include
+ the brackets!) The text should be enclosed in the appropriate
+ comment syntax for the file format. We also recommend that a
+ file or class name and description of purpose be included on the
+ same "printed page" as the copyright notice for easier
+ identification within third-party archives.
+
+ Copyright [yyyy] [name of copyright owner]
+
+ Licensed 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.
diff --git a/NOTICE b/NOTICE
new file mode 100644
index 0000000..ca3686b
--- /dev/null
+++ b/NOTICE
@@ -0,0 +1,8 @@
+Apache Sling Jackrabbit JSR-283 Access Control Manager Support
+Copyright 2008-2009 The Apache Software Foundation
+
+Apache Sling is based on source code originally developed
+by Day Software (http://www.day.com/).
+
+This product includes software developed at
+The Apache Software Foundation (http://www.apache.org/).
diff --git a/README.txt b/README.txt
new file mode 100644
index 0000000..3482a22
--- /dev/null
+++ b/README.txt
@@ -0,0 +1,37 @@
+Apache Sling Jackrabbit JSR-283 Access Control Manager Support
+
+Provides actions for the JSR-283 Access Control Manager.
+
+Disclaimer
+==========
+Apache Sling is an effort undergoing incubation at The Apache Software Foundation (ASF),
+sponsored by the Apache Jackrabbit PMC. Incubation is required of all newly accepted
+projects until a further review indicates that the infrastructure, communications,
+and decision making process have stabilized in a manner consistent with other
+successful ASF projects. While incubation status is not necessarily a reflection of
+the completeness or stability of the code, it does indicate that the project has yet
+to be fully endorsed by the ASF.
+
+Getting Started
+===============
+
+This component uses a Maven 2 (http://maven.apache.org/) build
+environment. It requires a Java 5 JDK (or higher) and Maven (http://maven.apache.org/)
+2.0.7 or later. We recommend to use the latest Maven version.
+
+If you have Maven 2 installed, you can compile and
+package the jar using the following command:
+
+ mvn package
+
+See the Maven 2 documentation for other build features.
+
+The latest source code for this component is available in the
+Subversion (http://subversion.tigris.org/) source repository of
+the Apache Software Foundation. If you have Subversion installed,
+you can checkout the latest source using the following command:
+
+ svn checkout http://svn.apache.org/repos/asf/incubator/sling/trunk/servlets/post
+
+See the Subversion documentation for other source control features.
+
diff --git a/pom.xml b/pom.xml
new file mode 100644
index 0000000..b51abe4
--- /dev/null
+++ b/pom.xml
@@ -0,0 +1,119 @@
+<project xmlns="http://maven.apache.org/POM/4.0.0"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>sling</artifactId>
+ <version>5-incubator-SNAPSHOT</version>
+ <relativePath>../../../parent/pom.xml</relativePath>
+ </parent>
+
+ <artifactId>org.apache.sling.jcr.jackrabbit.accessmanager</artifactId>
+ <packaging>bundle</packaging>
+ <version>2.0.0-incubator-SNAPSHOT</version>
+ <name>Apache Sling Jackrabbit JSR-283 Access Control Manager Support</name>
+ <description>
+ Provides SlingPostOperations for the Jackrabbit JSR-283 Access Control Manager.
+ </description>
+
+ <scm>
+ <connection>
+ scm:svn:http://svn.apache.org/repos/asf/incubator/sling/trunk/bundles/jcr/jackrabbit-accessmanager
+ </connection>
+ <developerConnection>
+ scm:svn:https://svn.apache.org/repos/asf/incubator/sling/trunk/bundles/jcr/jackrabbit-accessmanager
+ </developerConnection>
+ <url>
+ http://svn.apache.org/viewvc/incubator/sling/trunk/bundles/jcr/jackrabbit-accessmanager
+ </url>
+ </scm>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-scr-plugin</artifactId>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>maven-bundle-plugin</artifactId>
+ <extensions>true</extensions>
+ <configuration>
+ <instructions>
+ <Private-Package>
+ </Private-Package>
+ <Export-Package>
+ org.apache.sling.jcr.jackrabbit.accessmanager;version=${pom.version},
+ org.apache.sling.jcr.jackrabbit.accessmanager.post;version=${pom.version}
+ </Export-Package>
+ <Sling-Initial-Content></Sling-Initial-Content>
+ <Sling-Nodetypes></Sling-Nodetypes>
+ </instructions>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+
+ <reporting>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-javadoc-plugin</artifactId>
+ <configuration>
+ <!-- No javadocs -->
+ <excludePackageNames>
+ </excludePackageNames>
+ </configuration>
+ </plugin>
+ </plugins>
+ </reporting>
+
+ <dependencies>
+ <dependency>
+ <groupId>javax.servlet</groupId>
+ <artifactId>servlet-api</artifactId>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.commons.json</artifactId>
+ <version>2.0.3-incubator-SNAPSHOT</version>
+ </dependency>
+
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.api</artifactId>
+ <version>2.0.3-incubator-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.servlets.post</artifactId>
+ <version>2.0.3-incubator-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.jcr.jackrabbit.api</artifactId>
+ <version>2.0.3-incubator-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.jcr.base</artifactId>
+ <version>2.0.3-incubator-SNAPSHOT</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.jackrabbit</groupId>
+ <artifactId>jackrabbit-api</artifactId>
+ <version>1.5.0</version>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.osgi.core</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.felix</groupId>
+ <artifactId>org.osgi.compendium</artifactId>
+ </dependency>
+ </dependencies>
+</project>
\ No newline at end of file
diff --git a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/PrivilegesInfo.java b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/PrivilegesInfo.java
new file mode 100644
index 0000000..aef7a29
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/PrivilegesInfo.java
@@ -0,0 +1,616 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+import java.security.Principal;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.Set;
+
+import javax.jcr.Node;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.api.jsr283.security.AccessControlEntry;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlList;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlManager;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlPolicy;
+import org.apache.jackrabbit.api.jsr283.security.Privilege;
+import org.apache.jackrabbit.api.security.principal.PrincipalManager;
+import org.apache.sling.jcr.base.util.AccessControlUtil;
+
+/**
+ * Helper class to assist in the usage of access control from scripts.
+ */
+public class PrivilegesInfo {
+
+ /**
+ * Return the supported Privileges for the specified node.
+ *
+ * @param node the node to check
+ * @return array of Privileges
+ * @throws RepositoryException
+ */
+ public Privilege [] getSupportedPrivileges(Node node) throws RepositoryException {
+ return getSupportedPrivileges(node.getSession(), node.getPath());
+ }
+
+ /**
+ * Returns the supported privileges for the specified path.
+ *
+ * @param session the session for the current user
+ * @param absPath the path to get the privileges for
+ * @return array of Privileges
+ * @throws RepositoryException
+ */
+ public Privilege [] getSupportedPrivileges(Session session, String absPath) throws RepositoryException {
+ AccessControlManager accessControlManager = AccessControlUtil.getAccessControlManager(session);
+ Privilege[] supportedPrivileges = accessControlManager.getSupportedPrivileges(absPath);
+ return supportedPrivileges;
+ }
+
+ /**
+ * Wrapper class that holds the set of Privileges that are granted
+ * and/or denied for a specific principal.
+ */
+ public static class AccessRights {
+ private Set<Privilege> granted = new HashSet<Privilege>();
+ private Set<Privilege> denied = new HashSet<Privilege>();
+
+ private transient static ResourceBundle resBundle = null;
+ private ResourceBundle getResourceBundle(Locale locale) {
+ if (resBundle == null || !resBundle.getLocale().equals(locale)) {
+ resBundle = ResourceBundle.getBundle(getClass().getPackage().getName() + ".PrivilegesResources", locale);
+ }
+ return resBundle;
+ }
+
+
+ public Set<Privilege> getGranted() {
+ return granted;
+ }
+ public Set<Privilege> getDenied() {
+ return denied;
+ }
+
+ public String getPrivilegeSetDisplayName(Locale locale) {
+ if (denied != null && !denied.isEmpty()) {
+ //if there are any denied privileges, then this is a custom privilege set
+ return getResourceBundle(locale).getString("privilegeset.custom");
+ } else {
+ if (granted.isEmpty()) {
+ //appears to have an empty privilege set
+ return getResourceBundle(locale).getString("privilegeset.none");
+ }
+
+ if (granted.size() == 1) {
+ //check if the single privilege is jcr:all or jcr:read
+ Iterator<Privilege> iterator = granted.iterator();
+ Privilege next = iterator.next();
+ if ("jcr:all".equals(next.getName())) {
+ //full control privilege set
+ return getResourceBundle(locale).getString("privilegeset.all");
+ } else if ("jcr:read".equals(next.getName())) {
+ //readonly privilege set
+ return getResourceBundle(locale).getString("privilegeset.readonly");
+ }
+ } else if (granted.size() == 2) {
+ //check if the two privileges are jcr:read and jcr:write
+ Iterator<Privilege> iterator = granted.iterator();
+ Privilege next = iterator.next();
+ Privilege next2 = iterator.next();
+ if ( ("jcr:read".equals(next.getName()) && "jcr:write".equals(next2.getName())) ||
+ ("jcr:read".equals(next2.getName()) && "jcr:write".equals(next.getName())) ) {
+ //read/write privileges
+ return getResourceBundle(locale).getString("privilegeset.readwrite");
+ }
+ }
+
+ //some other set of privileges
+ return getResourceBundle(locale).getString("privilegeset.custom");
+ }
+ }
+ }
+
+ /**
+ * Returns the mapping of declared access rights that have been set for the resource at
+ * the given path.
+ *
+ * @param node the node to get the access rights for
+ * @return map of access rights. Key is the user/group principal, value contains the granted/denied privileges
+ * @throws RepositoryException
+ */
+ public Map<Principal, AccessRights> getDeclaredAccessRights(Node node) throws RepositoryException {
+ Map<Principal, AccessRights> accessRights = getDeclaredAccessRights(node.getSession(), node.getPath());
+ return accessRights;
+ }
+
+ /**
+ * Returns the mapping of declared access rights that have been set for the resource at
+ * the given path.
+ *
+ * @param session the current user session.
+ * @param absPath the path of the resource to get the access rights for
+ * @return map of access rights. Key is the user/group principal, value contains the granted/denied privileges
+ * @throws RepositoryException
+ */
+ public Map<Principal, AccessRights> getDeclaredAccessRights(Session session, String absPath) throws RepositoryException {
+ Map<Principal, AccessRights> accessMap = new LinkedHashMap<Principal, AccessRights>();
+ AccessControlEntry[] entries = getDeclaredAccessControlEntries(session, absPath);
+ if (entries != null) {
+ for (AccessControlEntry ace : entries) {
+ Principal principal = ace.getPrincipal();
+ AccessRights accessPrivleges = accessMap.get(principal);
+ if (accessPrivleges == null) {
+ accessPrivleges = new AccessRights();
+ accessMap.put(principal, accessPrivleges);
+ }
+ boolean allow = AccessControlUtil.isAllow(ace);
+ if (allow) {
+ accessPrivleges.getGranted().addAll(Arrays.asList(ace.getPrivileges()));
+ } else {
+ accessPrivleges.getDenied().addAll(Arrays.asList(ace.getPrivileges()));
+ }
+ }
+ }
+
+ return accessMap;
+ }
+
+ private AccessControlEntry[] getDeclaredAccessControlEntries(Session session, String absPath) throws RepositoryException {
+ AccessControlManager accessControlManager = AccessControlUtil.getAccessControlManager(session);
+ AccessControlPolicy[] policies = accessControlManager.getPolicies(absPath);
+ for (AccessControlPolicy accessControlPolicy : policies) {
+ if (accessControlPolicy instanceof AccessControlList) {
+ AccessControlEntry[] accessControlEntries = ((AccessControlList)accessControlPolicy).getAccessControlEntries();
+ return accessControlEntries;
+ }
+ }
+ return new AccessControlEntry[0];
+ }
+
+ /**
+ * Returns the declared access rights for the specified Node for the given
+ * principalId.
+ *
+ * @param node the JCR node to retrieve the access rights for
+ * @param principalId the principalId to get the access rights for
+ * @return access rights for the specified principal
+ * @throws RepositoryException
+ */
+ public AccessRights getDeclaredAccessRightsForPrincipal(Node node, String principalId) throws RepositoryException {
+ return getDeclaredAccessRightsForPrincipal(node.getSession(), node.getPath(), principalId);
+ }
+
+ /**
+ * Returns the declared access rights for the resource at the specified path for the given
+ * principalId.
+ *
+ * @param session the current JCR session
+ * @param absPath the path of the resource to retrieve the rights for
+ * @param principalId the principalId to get the access rights for
+ * @return access rights for the specified principal
+ * @throws RepositoryException
+ */
+ public AccessRights getDeclaredAccessRightsForPrincipal(Session session, String absPath, String principalId) throws RepositoryException {
+ AccessRights rights = new AccessRights();
+ if (principalId != null && principalId.length() > 0) {
+ AccessControlManager accessControlManager = AccessControlUtil.getAccessControlManager(session);
+ AccessControlPolicy[] policies = accessControlManager.getPolicies(absPath);
+ for (AccessControlPolicy accessControlPolicy : policies) {
+ if (accessControlPolicy instanceof AccessControlList) {
+ AccessControlEntry[] accessControlEntries = ((AccessControlList)accessControlPolicy).getAccessControlEntries();
+ for (AccessControlEntry ace : accessControlEntries) {
+ if (principalId.equals(ace.getPrincipal().getName())) {
+ boolean isAllow = AccessControlUtil.isAllow(ace);
+ if (isAllow) {
+ rights.getGranted().addAll(Arrays.asList(ace.getPrivileges()));
+ } else {
+ rights.getDenied().addAll(Arrays.asList(ace.getPrivileges()));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return rights;
+ }
+
+
+
+
+ /**
+ * Returns the mapping of effective access rights that have been set for the resource at
+ * the given path.
+ *
+ * @param node the node to get the access rights for
+ * @return map of access rights. Key is the user/group principal, value contains the granted/denied privileges
+ * @throws RepositoryException
+ */
+ public Map<Principal, AccessRights> getEffectiveAccessRights(Node node) throws RepositoryException {
+ Map<Principal, AccessRights> accessRights = getEffectiveAccessRights(node.getSession(), node.getPath());
+ return accessRights;
+ }
+
+ /**
+ * Returns the mapping of effective access rights that have been set for the resource at
+ * the given path.
+ *
+ * @param session the current user session.
+ * @param absPath the path of the resource to get the access rights for
+ * @return map of access rights. Key is the user/group principal, value contains the granted/denied privileges
+ * @throws RepositoryException
+ */
+ public Map<Principal, AccessRights> getEffectiveAccessRights(Session session, String absPath) throws RepositoryException {
+ Map<Principal, AccessRights> accessMap = new LinkedHashMap<Principal, AccessRights>();
+ AccessControlEntry[] entries = getEffectiveAccessControlEntries(session, absPath);
+ if (entries != null) {
+ for (AccessControlEntry ace : entries) {
+ Principal principal = ace.getPrincipal();
+ AccessRights accessPrivleges = accessMap.get(principal);
+ if (accessPrivleges == null) {
+ accessPrivleges = new AccessRights();
+ accessMap.put(principal, accessPrivleges);
+ }
+ boolean allow = AccessControlUtil.isAllow(ace);
+ if (allow) {
+ accessPrivleges.getGranted().addAll(Arrays.asList(ace.getPrivileges()));
+ } else {
+ accessPrivleges.getDenied().addAll(Arrays.asList(ace.getPrivileges()));
+ }
+ }
+ }
+
+ return accessMap;
+ }
+
+ private AccessControlEntry[] getEffectiveAccessControlEntries(Session session, String absPath) throws RepositoryException {
+ AccessControlManager accessControlManager = AccessControlUtil.getAccessControlManager(session);
+ AccessControlPolicy[] policies = accessControlManager.getEffectivePolicies(absPath);
+ for (AccessControlPolicy accessControlPolicy : policies) {
+ if (accessControlPolicy instanceof AccessControlList) {
+ AccessControlEntry[] accessControlEntries = ((AccessControlList)accessControlPolicy).getAccessControlEntries();
+ return accessControlEntries;
+ }
+ }
+ return new AccessControlEntry[0];
+ }
+
+ /**
+ * Returns the effective access rights for the specified Node for the given
+ * principalId.
+ *
+ * @param node the JCR node to retrieve the access rights for
+ * @param principalId the principalId to get the access rights for
+ * @return access rights for the specified principal
+ * @throws RepositoryException
+ */
+ public AccessRights getEffectiveAccessRightsForPrincipal(Node node, String principalId) throws RepositoryException {
+ return getEffectiveAccessRightsForPrincipal(node.getSession(), node.getPath(), principalId);
+ }
+
+ /**
+ * Returns the effective access rights for the resource at the specified path for the given
+ * principalId.
+ *
+ * @param session the current JCR session
+ * @param absPath the path of the resource to retrieve the rights for
+ * @param principalId the principalId to get the access rights for
+ * @return access rights for the specified principal
+ * @throws RepositoryException
+ */
+ public AccessRights getEffectiveAccessRightsForPrincipal(Session session, String absPath, String principalId) throws RepositoryException {
+ AccessRights rights = new AccessRights();
+ if (principalId != null && principalId.length() > 0) {
+ AccessControlManager accessControlManager = AccessControlUtil.getAccessControlManager(session);
+ AccessControlPolicy[] policies = accessControlManager.getEffectivePolicies(absPath);
+ for (AccessControlPolicy accessControlPolicy : policies) {
+ if (accessControlPolicy instanceof AccessControlList) {
+ AccessControlEntry[] accessControlEntries = ((AccessControlList)accessControlPolicy).getAccessControlEntries();
+ for (AccessControlEntry ace : accessControlEntries) {
+ if (principalId.equals(ace.getPrincipal().getName())) {
+ boolean isAllow = AccessControlUtil.isAllow(ace);
+ if (isAllow) {
+ rights.getGranted().addAll(Arrays.asList(ace.getPrivileges()));
+ } else {
+ rights.getDenied().addAll(Arrays.asList(ace.getPrivileges()));
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return rights;
+ }
+
+
+
+ /**
+ * Checks whether the current user has been granted privileges
+ * to add children to the specified node.
+ *
+ * @param node the node to check
+ * @return true if the current user has the privileges, false otherwise
+ */
+ public boolean canAddChildren(Node node) {
+ try {
+ return canAddChildren(node.getSession(), node.getPath());
+ } catch (RepositoryException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether the current user has been granted privileges
+ * to add children to the specified path.
+ *
+ * @param session the JCR session of the current user
+ * @param absPath the path of the resource to check
+ * @return true if the current user has the privileges, false otherwise
+ */
+ public boolean canAddChildren(Session session, String absPath) {
+ try {
+ AccessControlManager accessControlManager = AccessControlUtil.getAccessControlManager(session);
+ return accessControlManager.hasPrivileges(absPath, new Privilege[] {
+ accessControlManager.privilegeFromName(Privilege.JCR_ADD_CHILD_NODES)
+ });
+ } catch (RepositoryException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether the current user has been granted privileges
+ * to delete children to the specified node.
+ *
+ * @param node the node to check
+ * @return true if the current user has the privileges, false otherwise
+ */
+ public boolean canDeleteChildren(Node node) {
+ try {
+ return canDeleteChildren(node.getSession(), node.getPath());
+ } catch (RepositoryException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether the current user has been granted privileges
+ * to delete children of the specified path.
+ *
+ * @param session the JCR session of the current user
+ * @param absPath the path of the resource to check
+ * @return true if the current user has the privileges, false otherwise
+ */
+ public boolean canDeleteChildren(Session session, String absPath) {
+ try {
+ AccessControlManager accessControlManager = AccessControlUtil.getAccessControlManager(session);
+
+ return accessControlManager.hasPrivileges(absPath, new Privilege[] {
+ accessControlManager.privilegeFromName(Privilege.JCR_REMOVE_CHILD_NODES)
+ });
+ } catch (RepositoryException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether the current user has been granted privileges
+ * to delete the specified node.
+ *
+ * @param node the node to check
+ * @return true if the current user has the privileges, false otherwise
+ */
+ public boolean canDelete(Node node) {
+ try {
+ return canDelete(node.getSession(), node.getPath());
+ } catch (RepositoryException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether the current user has been granted privileges
+ * to delete the specified path.
+ *
+ * @param session the JCR session of the current user
+ * @param absPath the path of the resource to check
+ * @return true if the current user has the privileges, false otherwise
+ */
+ public boolean canDelete(Session session, String absPath) {
+ try {
+ AccessControlManager accessControlManager = AccessControlUtil.getAccessControlManager(session);
+
+ String parentPath = absPath.substring(0, absPath.lastIndexOf('/'));
+ boolean canDelete = accessControlManager.hasPrivileges(absPath, new Privilege[] {
+ accessControlManager.privilegeFromName(Privilege.JCR_REMOVE_NODE)
+ }) && canDeleteChildren(session, parentPath);
+ return canDelete;
+ } catch (RepositoryException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether the current user has been granted privileges
+ * to modify properties of the specified node.
+ *
+ * @param node the node to check
+ * @return true if the current user has the privileges, false otherwise
+ */
+ public boolean canModifyProperties(Node node) {
+ try {
+ return canModifyProperties(node.getSession(), node.getPath());
+ } catch (RepositoryException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether the current user has been granted privileges
+ * to modify properties of the specified path.
+ *
+ * @param session the JCR session of the current user
+ * @param absPath the path of the resource to check
+ * @return true if the current user has the privileges, false otherwise
+ */
+ public boolean canModifyProperties(Session session, String absPath) {
+ try {
+ AccessControlManager accessControlManager = AccessControlUtil.getAccessControlManager(session);
+ return accessControlManager.hasPrivileges(absPath, new Privilege[] {
+ accessControlManager.privilegeFromName(Privilege.JCR_MODIFY_PROPERTIES)
+ });
+ } catch (RepositoryException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether the current user has been granted privileges
+ * to read the access control of the specified node.
+ *
+ * @param node the node to check
+ * @return true if the current user has the privileges, false otherwise
+ */
+ public boolean canReadAccessControl(Node node) {
+ try {
+ return canReadAccessControl(node.getSession(), node.getPath());
+ } catch (RepositoryException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether the current user has been granted privileges
+ * to read the access control of the specified path.
+ *
+ * @param session the JCR session of the current user
+ * @param absPath the path of the resource to check
+ * @return true if the current user has the privileges, false otherwise
+ */
+ public boolean canReadAccessControl(Session session, String absPath) {
+ try {
+ AccessControlManager accessControlManager = AccessControlUtil.getAccessControlManager(session);
+ return accessControlManager.hasPrivileges(absPath, new Privilege[] {
+ accessControlManager.privilegeFromName(Privilege.JCR_READ_ACCESS_CONTROL)
+ });
+ } catch (RepositoryException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether the current user has been granted privileges
+ * to modify the access control of the specified node.
+ *
+ * @param node the node to check
+ * @return true if the current user has the privileges, false otherwise
+ */
+ public boolean canModifyAccessControl(Node node) {
+ try {
+ return canModifyAccessControl(node.getSession(), node.getPath());
+ } catch (RepositoryException e) {
+ return false;
+ }
+ }
+
+ /**
+ * Checks whether the current user has been granted privileges
+ * to modify the access control of the specified path.
+ *
+ * @param session the JCR session of the current user
+ * @param absPath the path of the resource to check
+ * @return true if the current user has the privileges, false otherwise
+ */
+ public boolean canModifyAccessControl(Session session, String absPath) {
+ try {
+ AccessControlManager accessControlManager = AccessControlUtil.getAccessControlManager(session);
+ return accessControlManager.hasPrivileges(absPath, new Privilege[] {
+ accessControlManager.privilegeFromName(Privilege.JCR_MODIFY_ACCESS_CONTROL)
+ });
+ } catch (RepositoryException e) {
+ return false;
+ }
+ }
+
+
+ /**
+ * Checks whether the current user has been granted privileges
+ * to update the properties of the specified principal.
+ *
+ * @param session the JCR session for the current user
+ * @param principalID the id of the principal to check
+ * @return true if the current user has the privileges, false otherwise
+ */
+ public boolean canUpdateAuthorizable(Session session, String principalID) {
+ try {
+ PrincipalManager principalManager = AccessControlUtil.getPrincipalManager(session);
+ Principal principal = principalManager.getPrincipal(principalID);
+ if (principal == null) {
+ return false;
+ }
+
+ String path = getAuthorizableItemPath(principal);
+ return canModifyProperties(session, path);
+ } catch (Exception e) {
+ //just eat it.
+ return false;
+ }
+ }
+ private String getAuthorizableItemPath(Principal principal)
+ throws NoSuchMethodException, IllegalAccessException,
+ InvocationTargetException {
+ //should check if principal implements ItemBasedPrincipal, but it is not visible here so use reflection instead
+ Method method = principal.getClass().getMethod("getPath");
+ String path = (String)method.invoke(principal);
+ return path;
+ }
+
+ /**
+ * Checks whether the current user has been granted privileges
+ * to delete the specified principal.
+ *
+ * @param session the JCR session for the current user
+ * @param principalID the id of the principal to check
+ * @return true if the current user has the privileges, false otherwise
+ */
+ public boolean canDeleteAuthorizable(Session session, String principalID) {
+ try {
+ PrincipalManager principalManager = AccessControlUtil.getPrincipalManager(session);
+ Principal principal = principalManager.getPrincipal(principalID);
+ if (principal == null) {
+ return false;
+ }
+
+ //should check if principal implements ItemBasedPrincipal, but it is not visible here so use reflection instead
+ String path = getAuthorizableItemPath(principal);
+ return canDelete(session, path);
+ } catch (Exception e) {
+ //just eat it.
+ return false;
+ }
+ }
+}
diff --git a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractAccessPostServlet.java b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractAccessPostServlet.java
new file mode 100644
index 0000000..aa9cf4c
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/AbstractAccessPostServlet.java
@@ -0,0 +1,254 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager.post;
+
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.resource.ResourceNotFoundException;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.api.servlets.HtmlResponse;
+import org.apache.sling.api.servlets.SlingAllMethodsServlet;
+import org.apache.sling.api.wrappers.SlingRequestPaths;
+import org.apache.sling.servlets.post.Modification;
+import org.apache.sling.servlets.post.SlingPostConstants;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Base class for all the POST servlets for the AccessManager operations
+ */
+public abstract class AbstractAccessPostServlet extends SlingAllMethodsServlet {
+ private static final long serialVersionUID = -5918670409789895333L;
+
+ /**
+ * default log
+ */
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ /* (non-Javadoc)
+ * @see org.apache.sling.api.servlets.SlingAllMethodsServlet#doPost(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.SlingHttpServletResponse)
+ */
+ @Override
+ protected void doPost(SlingHttpServletRequest request,
+ SlingHttpServletResponse httpResponse) throws ServletException,
+ IOException {
+ // prepare the response
+ HtmlResponse htmlResponse = new HtmlResponse();
+ htmlResponse.setReferer(request.getHeader("referer"));
+
+ // calculate the paths
+ String path = getItemPath(request);
+ htmlResponse.setPath(path);
+
+ // location
+ htmlResponse.setLocation(externalizePath(request, path));
+
+ // parent location
+ path = ResourceUtil.getParent(path);
+ if (path != null) {
+ htmlResponse.setParentLocation(externalizePath(request, path));
+ }
+
+ Session session = request.getResourceResolver().adaptTo(Session.class);
+
+ final List<Modification> changes = new ArrayList<Modification>();
+
+ try {
+ handleOperation(request, htmlResponse, changes);
+
+ //TODO: maybe handle SlingAuthorizablePostProcessor handlers here
+
+ // set changes on html response
+ for(Modification change : changes) {
+ switch ( change.getType() ) {
+ case MODIFY : htmlResponse.onModified(change.getSource()); break;
+ case DELETE : htmlResponse.onDeleted(change.getSource()); break;
+ case MOVE : htmlResponse.onMoved(change.getSource(), change.getDestination()); break;
+ case COPY : htmlResponse.onCopied(change.getSource(), change.getDestination()); break;
+ case CREATE : htmlResponse.onCreated(change.getSource()); break;
+ case ORDER : htmlResponse.onChange("ordered", change.getSource(), change.getDestination()); break;
+ }
+ }
+
+ if (session.hasPendingChanges()) {
+ session.save();
+ }
+ } catch (ResourceNotFoundException rnfe) {
+ htmlResponse.setStatus(HttpServletResponse.SC_NOT_FOUND,
+ rnfe.getMessage());
+ } catch (Throwable throwable) {
+ log.debug("Exception while handling POST "
+ + request.getResource().getPath() + " with "
+ + getClass().getName(), throwable);
+ htmlResponse.setError(throwable);
+ } finally {
+ try {
+ if (session.hasPendingChanges()) {
+ session.refresh(false);
+ }
+ } catch (RepositoryException e) {
+ log.warn("RepositoryException in finally block: {}",
+ e.getMessage(), e);
+ }
+ }
+
+ // check for redirect URL if processing succeeded
+ if (htmlResponse.isSuccessful()) {
+ String redirect = getRedirectUrl(request, htmlResponse);
+ if (redirect != null) {
+ httpResponse.sendRedirect(redirect);
+ return;
+ }
+ }
+
+ // create a html response and send if unsuccessful or no redirect
+ htmlResponse.send(httpResponse, isSetStatus(request));
+ }
+
+ /**
+ * Extending Servlet should implement this operation to do the work
+ *
+ * @param request the sling http request to process
+ * @param htmlResponse the response
+ * @param changes
+ */
+ abstract protected void handleOperation(SlingHttpServletRequest request,
+ HtmlResponse htmlResponse, List<Modification> changes) throws RepositoryException;
+
+
+ /**
+ * compute redirect URL (SLING-126)
+ *
+ * @param ctx the post processor
+ * @return the redirect location or <code>null</code>
+ */
+ protected String getRedirectUrl(HttpServletRequest request, HtmlResponse ctx) {
+ // redirect param has priority (but see below, magic star)
+ String result = request.getParameter(SlingPostConstants.RP_REDIRECT_TO);
+ if (result != null && ctx.getPath() != null) {
+
+ // redirect to created/modified Resource
+ int star = result.indexOf('*');
+ if (star >= 0) {
+ StringBuffer buf = new StringBuffer();
+
+ // anything before the star
+ if (star > 0) {
+ buf.append(result.substring(0, star));
+ }
+
+ // append the name of the manipulated node
+ buf.append(ResourceUtil.getName(ctx.getPath()));
+
+ // anything after the star
+ if (star < result.length() - 1) {
+ buf.append(result.substring(star + 1));
+ }
+
+ // use the created path as the redirect result
+ result = buf.toString();
+
+ } else if (result.endsWith(SlingPostConstants.DEFAULT_CREATE_SUFFIX)) {
+ // if the redirect has a trailing slash, append modified node
+ // name
+ result = result.concat(ResourceUtil.getName(ctx.getPath()));
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Will redirect to " + result);
+ }
+ }
+ return result;
+ }
+
+ protected boolean isSetStatus(SlingHttpServletRequest request) {
+ String statusParam = request.getParameter(SlingPostConstants.RP_STATUS);
+ if (statusParam == null) {
+ log.debug(
+ "getStatusMode: Parameter {} not set, assuming standard status code",
+ SlingPostConstants.RP_STATUS);
+ return true;
+ }
+
+ if (SlingPostConstants.STATUS_VALUE_BROWSER.equals(statusParam)) {
+ log.debug(
+ "getStatusMode: Parameter {} asks for user-friendly status code",
+ SlingPostConstants.RP_STATUS);
+ return false;
+ }
+
+ if (SlingPostConstants.STATUS_VALUE_STANDARD.equals(statusParam)) {
+ log.debug(
+ "getStatusMode: Parameter {} asks for standard status code",
+ SlingPostConstants.RP_STATUS);
+ return true;
+ }
+
+ log.debug(
+ "getStatusMode: Parameter {} set to unknown value {}, assuming standard status code",
+ SlingPostConstants.RP_STATUS);
+ return true;
+ }
+
+ // ------ These methods were copied from AbstractSlingPostOperation ------
+
+ /**
+ * Returns the path of the resource of the request as the item path.
+ * <p>
+ * This method may be overwritten by extension if the operation has
+ * different requirements on path processing.
+ */
+ protected String getItemPath(SlingHttpServletRequest request) {
+ return request.getResource().getPath();
+ }
+
+ /**
+ * Returns an external form of the given path prepending the context path
+ * and appending a display extension.
+ *
+ * @param path the path to externalize
+ * @return the url
+ */
+ protected final String externalizePath(SlingHttpServletRequest request,
+ String path) {
+ StringBuffer ret = new StringBuffer();
+ ret.append(SlingRequestPaths.getContextPath(request));
+ ret.append(request.getResourceResolver().map(path));
+
+ // append optional extension
+ String ext = request.getParameter(SlingPostConstants.RP_DISPLAY_EXTENSION);
+ if (ext != null && ext.length() > 0) {
+ if (ext.charAt(0) != '.') {
+ ret.append('.');
+ }
+ ret.append(ext);
+ }
+
+ return ret.toString();
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/DeleteAcesServlet.java b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/DeleteAcesServlet.java
new file mode 100644
index 0000000..bcb0a3e
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/DeleteAcesServlet.java
@@ -0,0 +1,128 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager.post;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import javax.jcr.Item;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.api.jsr283.security.AccessControlEntry;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlList;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlManager;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlPolicy;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlPolicyIterator;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceNotFoundException;
+import org.apache.sling.api.servlets.HtmlResponse;
+import org.apache.sling.jcr.base.util.AccessControlUtil;
+import org.apache.sling.servlets.post.Modification;
+import org.apache.sling.servlets.post.SlingPostConstants;
+
+/**
+ * Sling Post Servlet implementation for deleting the ACE for a set of principals on
+ * a JCR resource.
+ *
+ * @scr.component immediate="true"
+ * @scr.service interface="javax.servlet.Servlet"
+ * @scr.property name="sling.servlet.resourceTypes" value="sling/servlet/default"
+ * @scr.property name="sling.servlet.methods" value="POST"
+ * @scr.property name="sling.servlet.selectors" value="deleteAce"
+ */
+public class DeleteAcesServlet extends AbstractAccessPostServlet {
+ private static final long serialVersionUID = 3784866802938282971L;
+
+ /* (non-Javadoc)
+ * @see org.apache.sling.jackrabbit.accessmanager.post.AbstractAccessPostServlet#handleOperation(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
+ */
+ @Override
+ protected void handleOperation(SlingHttpServletRequest request,
+ HtmlResponse htmlResponse, List<Modification> changes)
+ throws RepositoryException {
+
+ String[] applyTo = request.getParameterValues(SlingPostConstants.RP_APPLY_TO);
+ if (applyTo == null) {
+ throw new RepositoryException("principalIds were not sumitted.");
+ } else {
+ String resourcePath = null;
+ Resource resource = request.getResource();
+ if (resource == null) {
+ throw new ResourceNotFoundException("Resource not found.");
+ } else {
+ Item item = resource.adaptTo(Item.class);
+ if (item != null) {
+ resourcePath = item.getPath();
+ } else {
+ throw new ResourceNotFoundException("Resource is not a JCR Node");
+ }
+ }
+
+ Session session = request.getResourceResolver().adaptTo(Session.class);
+ if (session == null) {
+ throw new RepositoryException("JCR Session not found");
+ }
+
+ //load the principalIds array into a set for quick lookup below
+ Set<String> pidSet = new HashSet<String>();
+ pidSet.addAll(Arrays.asList(applyTo));
+
+ try {
+ AccessControlManager accessControlManager = AccessControlUtil.getAccessControlManager(session);
+ AccessControlList updatedAcl = null;
+ AccessControlPolicyIterator applicablePolicies = accessControlManager.getApplicablePolicies(resourcePath);
+ while (applicablePolicies.hasNext()) {
+ AccessControlPolicy policy = applicablePolicies.nextAccessControlPolicy();
+ if (policy instanceof AccessControlList) {
+ updatedAcl = (AccessControlList)policy;
+ break;
+ }
+ }
+ if (updatedAcl == null) {
+ throw new RepositoryException("Unable to find an access control policy to update.");
+ }
+
+ //keep track of the existing Aces for the target principal
+ AccessControlEntry[] accessControlEntries = updatedAcl.getAccessControlEntries();
+ List<AccessControlEntry> oldAces = new ArrayList<AccessControlEntry>();
+ for (AccessControlEntry ace : accessControlEntries) {
+ if (pidSet.contains(ace.getPrincipal().getName())) {
+ oldAces.add(ace);
+ }
+ }
+
+ //remove the old aces
+ if (!oldAces.isEmpty()) {
+ for (AccessControlEntry ace : oldAces) {
+ updatedAcl.removeAccessControlEntry(ace);
+ }
+ }
+
+ //apply the changed policy
+ accessControlManager.setPolicy(resourcePath, updatedAcl);
+ } catch (RepositoryException re) {
+ throw new RepositoryException("Failed to delete access control.", re);
+ }
+ }
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/GetAclServlet.java b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/GetAclServlet.java
new file mode 100644
index 0000000..1104e24
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/GetAclServlet.java
@@ -0,0 +1,180 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager.post;
+
+import java.io.IOException;
+import java.security.Principal;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.Map.Entry;
+
+import javax.jcr.AccessDeniedException;
+import javax.jcr.Item;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletResponse;
+
+import org.apache.jackrabbit.api.jsr283.security.AccessControlEntry;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlList;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlManager;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlPolicy;
+import org.apache.jackrabbit.api.jsr283.security.Privilege;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.SlingHttpServletResponse;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceNotFoundException;
+import org.apache.sling.api.servlets.SlingAllMethodsServlet;
+import org.apache.sling.commons.json.JSONObject;
+import org.apache.sling.jcr.base.util.AccessControlUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Sling GET servlet implementation for dumping the declared ACL of a resource
+ * to JSON.
+ *
+ * @scr.component immediate="true"
+ * @scr.service interface="javax.servlet.Servlet"
+ * @scr.property name="sling.servlet.resourceTypes" value="sling/servlet/default"
+ * @scr.property name="sling.servlet.methods" value="GET"
+ * @scr.property name="sling.servlet.selectors" value="acl"
+ * @scr.property name="sling.servlet.extensions " value="json"
+ */
+public class GetAclServlet extends SlingAllMethodsServlet {
+ private static final long serialVersionUID = 3391376559396223184L;
+
+ /**
+ * default log
+ */
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ /* (non-Javadoc)
+ * @see org.apache.sling.api.servlets.SlingSafeMethodsServlet#doGet(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.SlingHttpServletResponse)
+ */
+ @Override
+ protected void doGet(SlingHttpServletRequest request,
+ SlingHttpServletResponse response) throws ServletException,
+ IOException {
+
+ try {
+ Session session = request.getResourceResolver().adaptTo(Session.class);
+ if (session == null) {
+ throw new RepositoryException("JCR Session not found");
+ }
+
+ String resourcePath = null;
+ Resource resource = request.getResource();
+ if (resource == null) {
+ throw new ResourceNotFoundException("Resource not found.");
+ } else {
+ Item item = resource.adaptTo(Item.class);
+ if (item != null) {
+ resourcePath = item.getPath();
+ } else {
+ throw new ResourceNotFoundException("Resource is not a JCR Node");
+ }
+ }
+
+ AccessControlEntry[] declaredAccessControlEntries = getDeclaredAccessControlEntries(session, resourcePath);
+ Map<String, Map<String, Set<String>>> aclMap = new LinkedHashMap<String, Map<String,Set<String>>>();
+ for (AccessControlEntry ace : declaredAccessControlEntries) {
+ Principal principal = ace.getPrincipal();
+ Map<String, Set<String>> map = aclMap.get(principal.getName());
+ if (map == null) {
+ map = new LinkedHashMap<String, Set<String>>();
+ aclMap.put(principal.getName(), map);
+ }
+
+ boolean allow = AccessControlUtil.isAllow(ace);
+ if (allow) {
+ Set<String> grantedSet = map.get("granted");
+ if (grantedSet == null) {
+ grantedSet = new LinkedHashSet<String>();
+ map.put("granted", grantedSet);
+ }
+ Privilege[] privileges = ace.getPrivileges();
+ for (Privilege privilege : privileges) {
+ grantedSet.add(privilege.getName());
+ }
+ } else {
+ Set<String> deniedSet = map.get("denied");
+ if (deniedSet == null) {
+ deniedSet = new LinkedHashSet<String>();
+ map.put("denied", deniedSet);
+ }
+ Privilege[] privileges = ace.getPrivileges();
+ for (Privilege privilege : privileges) {
+ deniedSet.add(privilege.getName());
+ }
+ }
+ }
+
+
+ response.setContentType("application/json");
+ response.setCharacterEncoding("UTF-8");
+
+ JSONObject jsonObj = new JSONObject();
+ Set<Entry<String, Map<String, Set<String>>>> entrySet = aclMap.entrySet();
+ for (Entry<String, Map<String, Set<String>>> entry : entrySet) {
+ String principalName = entry.getKey();
+ Map<String, Set<String>> value = entry.getValue();
+
+ JSONObject aceObject = new JSONObject();
+ Set<String> grantedSet = value.get("granted");
+ if (grantedSet != null) {
+ aceObject.put("granted", grantedSet);
+ }
+
+ Set<String> deniedSet = value.get("denied");
+ if (deniedSet != null) {
+ aceObject.put("denied", deniedSet);
+ }
+
+ jsonObj.put(principalName, aceObject);
+ }
+
+
+ // do the dump
+ jsonObj.write(response.getWriter());
+ } catch (AccessDeniedException ade) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND);
+ } catch (ResourceNotFoundException rnfe) {
+ response.sendError(HttpServletResponse.SC_NOT_FOUND, rnfe.getMessage());
+ } catch (Throwable throwable) {
+ log.debug("Exception while handling GET "
+ + request.getResource().getPath() + " with "
+ + getClass().getName(), throwable);
+ throw new ServletException(throwable);
+ }
+ }
+
+ private AccessControlEntry[] getDeclaredAccessControlEntries(Session session, String absPath) throws RepositoryException {
+ AccessControlManager accessControlManager = AccessControlUtil.getAccessControlManager(session);
+ AccessControlPolicy[] policies = accessControlManager.getPolicies(absPath);
+ for (AccessControlPolicy accessControlPolicy : policies) {
+ if (accessControlPolicy instanceof AccessControlList) {
+ AccessControlEntry[] accessControlEntries = ((AccessControlList)accessControlPolicy).getAccessControlEntries();
+ return accessControlEntries;
+ }
+ }
+ return new AccessControlEntry[0];
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/ModifyAceServlet.java b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/ModifyAceServlet.java
new file mode 100644
index 0000000..b98f7ac
--- /dev/null
+++ b/src/main/java/org/apache/sling/jcr/jackrabbit/accessmanager/post/ModifyAceServlet.java
@@ -0,0 +1,241 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.sling.jcr.jackrabbit.accessmanager.post;
+
+import java.security.Principal;
+import java.util.ArrayList;
+import java.util.Enumeration;
+import java.util.List;
+
+import javax.jcr.Item;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.apache.jackrabbit.api.jsr283.security.AccessControlEntry;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlList;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlManager;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlPolicy;
+import org.apache.jackrabbit.api.jsr283.security.AccessControlPolicyIterator;
+import org.apache.jackrabbit.api.jsr283.security.Privilege;
+import org.apache.jackrabbit.api.security.user.Authorizable;
+import org.apache.jackrabbit.api.security.user.UserManager;
+import org.apache.sling.api.SlingHttpServletRequest;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceNotFoundException;
+import org.apache.sling.api.servlets.HtmlResponse;
+import org.apache.sling.jcr.base.util.AccessControlUtil;
+import org.apache.sling.servlets.post.Modification;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Sling Post Servlet implementation for modifying the ACE for a principal on
+ * a JCR resource.
+ *
+ * @scr.component immediate="true"
+ * @scr.service interface="javax.servlet.Servlet"
+ * @scr.property name="sling.servlet.resourceTypes" value="sling/servlet/default"
+ * @scr.property name="sling.servlet.methods" value="POST"
+ * @scr.property name="sling.servlet.selectors" value="modifyAce"
+ */
+public class ModifyAceServlet extends AbstractAccessPostServlet {
+ private static final long serialVersionUID = -9182485466670280437L;
+
+ /**
+ * default log
+ */
+ private final Logger log = LoggerFactory.getLogger(getClass());
+
+ /* (non-Javadoc)
+ * @see org.apache.sling.jackrabbit.accessmanager.post.AbstractAccessPostServlet#handleOperation(org.apache.sling.api.SlingHttpServletRequest, org.apache.sling.api.servlets.HtmlResponse, java.util.List)
+ */
+ @SuppressWarnings("unchecked")
+ @Override
+ protected void handleOperation(SlingHttpServletRequest request,
+ HtmlResponse htmlResponse, List<Modification> changes)
+ throws RepositoryException {
+ Session session = request.getResourceResolver().adaptTo(Session.class);
+ if (session == null) {
+ throw new RepositoryException("JCR Session not found");
+ }
+
+ String principalId = request.getParameter("principalId");
+ if (principalId == null) {
+ throw new RepositoryException("principalId was not submitted.");
+ }
+ UserManager userManager = AccessControlUtil.getUserManager(session);
+ Authorizable authorizable = userManager.getAuthorizable(principalId);
+ if (authorizable == null) {
+ throw new RepositoryException("No principal found for id: " + principalId);
+ }
+
+ String resourcePath = null;
+ Resource resource = request.getResource();
+ if (resource == null) {
+ throw new ResourceNotFoundException("Resource not found.");
+ } else {
+ Item item = resource.adaptTo(Item.class);
+ if (item != null) {
+ resourcePath = item.getPath();
+ } else {
+ throw new ResourceNotFoundException("Resource is not a JCR Node");
+ }
+ }
+
+
+ List<String> grantedPrivilegeNames = new ArrayList<String>();
+ List<String> deniedPrivilegeNames = new ArrayList<String>();
+ Enumeration parameterNames = request.getParameterNames();
+ while (parameterNames.hasMoreElements()) {
+ Object nextElement = parameterNames.nextElement();
+ if (nextElement instanceof String) {
+ String paramName = (String)nextElement;
+ if (paramName.startsWith("privilege@")) {
+ String parameterValue = request.getParameter(paramName);
+ if (parameterValue != null && parameterValue.length() > 0) {
+ if ("granted".equals(parameterValue)) {
+ String privilegeName = paramName.substring(10);
+ grantedPrivilegeNames.add(privilegeName);
+ } else if ("denied".equals(parameterValue)) {
+ String privilegeName = paramName.substring(10);
+ deniedPrivilegeNames.add(privilegeName);
+ }
+ }
+ }
+ }
+ }
+
+ try {
+ AccessControlManager accessControlManager = AccessControlUtil.getAccessControlManager(session);
+ AccessControlList updatedAcl = null;
+ AccessControlPolicyIterator applicablePolicies = accessControlManager.getApplicablePolicies(resourcePath);
+ while (applicablePolicies.hasNext()) {
+ AccessControlPolicy policy = applicablePolicies.nextAccessControlPolicy();
+ if (policy instanceof AccessControlList) {
+ updatedAcl = (AccessControlList)policy;
+ break;
+ }
+ }
+ if (updatedAcl == null) {
+ throw new RepositoryException("Unable to find an access conrol policy to update.");
+ }
+
+ StringBuilder oldPrivileges = null;
+ StringBuilder newPrivileges = null;
+ if (log.isDebugEnabled()) {
+ oldPrivileges = new StringBuilder();
+ newPrivileges = new StringBuilder();
+ }
+
+ //keep track of the existing Aces for the target principal
+ AccessControlEntry[] accessControlEntries = updatedAcl.getAccessControlEntries();
+ List<AccessControlEntry> oldAces = new ArrayList<AccessControlEntry>();
+ for (AccessControlEntry ace : accessControlEntries) {
+ if (principalId.equals(ace.getPrincipal().getName())) {
+ if (log.isDebugEnabled()) {
+ log.debug("Found Existing ACE for principal {0} on resource: ", new Object[] {principalId, resourcePath});
+ }
+ oldAces.add(ace);
+
+ if (log.isDebugEnabled()) {
+ //collect the information for debug logging
+ boolean isAllow = AccessControlUtil.isAllow(ace);
+ Privilege[] privileges = ace.getPrivileges();
+ for (Privilege privilege : privileges) {
+ if (oldPrivileges.length() > 0) {
+ oldPrivileges.append(", "); //separate entries by commas
+ }
+ if (isAllow) {
+ oldPrivileges.append("granted=");
+ } else {
+ oldPrivileges.append("denied=");
+ }
+ oldPrivileges.append(privilege.getName());
+ }
+ }
+ }
+ }
+
+ //remove the old aces
+ if (!oldAces.isEmpty()) {
+ for (AccessControlEntry ace : oldAces) {
+ updatedAcl.removeAccessControlEntry(ace);
+ }
+ }
+
+ //add a fresh ACE with the granted privileges
+ List<Privilege> grantedPrivilegeList = new ArrayList<Privilege>();
+ for (String name : grantedPrivilegeNames) {
+ if (name.length() == 0) {
+ continue; //empty, skip it.
+ }
+ Privilege privilege = accessControlManager.privilegeFromName(name);
+ grantedPrivilegeList.add(privilege);
+
+ if (log.isDebugEnabled()) {
+ if (newPrivileges.length() > 0) {
+ newPrivileges.append(", "); //separate entries by commas
+ }
+ newPrivileges.append("granted=");
+ newPrivileges.append(privilege.getName());
+ }
+ }
+ if (grantedPrivilegeList.size() > 0) {
+ Principal principal = authorizable.getPrincipal();
+ updatedAcl.addAccessControlEntry(principal, grantedPrivilegeList.toArray(new Privilege[grantedPrivilegeList.size()]));
+ }
+
+ //if the authorizable is a user (not a group) process any denied privileges
+ if (!authorizable.isGroup()) {
+ //add a fresh ACE with the denied privileges
+ List<Privilege> deniedPrivilegeList = new ArrayList<Privilege>();
+ for (String name : deniedPrivilegeNames) {
+ if (name.length() == 0) {
+ continue; //empty, skip it.
+ }
+ Privilege privilege = accessControlManager.privilegeFromName(name);
+ deniedPrivilegeList.add(privilege);
+
+ if (log.isDebugEnabled()) {
+ if (newPrivileges.length() > 0) {
+ newPrivileges.append(", "); //separate entries by commas
+ }
+ newPrivileges.append("denied=");
+ newPrivileges.append(privilege.getName());
+ }
+ }
+ if (deniedPrivilegeList.size() > 0) {
+ Principal principal = authorizable.getPrincipal();
+ AccessControlUtil.addEntry(updatedAcl, principal, deniedPrivilegeList.toArray(new Privilege[deniedPrivilegeList.size()]), false);
+ }
+ }
+
+ accessControlManager.setPolicy(resourcePath, updatedAcl);
+ if (session.hasPendingChanges()) {
+ session.save();
+ }
+
+ if (log.isDebugEnabled()) {
+ log.debug("Updated ACE for principalId {0} for resource {1) from {2} to {3}", new Object [] {
+ authorizable.getID(), resourcePath, oldPrivileges.toString(), newPrivileges.toString()
+ });
+ }
+ } catch (RepositoryException re) {
+ throw new RepositoryException("Failed to create ace.", re);
+ }
+ }
+}
diff --git a/src/main/resources/OSGI-INF/metatype/metatype.properties b/src/main/resources/OSGI-INF/metatype/metatype.properties
new file mode 100644
index 0000000..f9e0714
--- /dev/null
+++ b/src/main/resources/OSGI-INF/metatype/metatype.properties
@@ -0,0 +1,25 @@
+#
+# 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.
+#
+
+
+#
+# This file contains localization strings for configuration labels and
+# descriptions as used in the metatype.xml descriptor generated by the
+# the Sling SCR plugin
+
diff --git a/src/main/resources/org/apache/sling/jcr/jackrabbit/accessmanager/PrivilegesResources.properties b/src/main/resources/org/apache/sling/jcr/jackrabbit/accessmanager/PrivilegesResources.properties
new file mode 100644
index 0000000..a7d1083
--- /dev/null
+++ b/src/main/resources/org/apache/sling/jcr/jackrabbit/accessmanager/PrivilegesResources.properties
@@ -0,0 +1,23 @@
+#
+# 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.
+
+privilegeset.all=Full Control
+privilegeset.readonly=Read Only
+privilegeset.readwrite=Read/Write
+privilegeset.none=None
+privilegeset.custom=Custom
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
"commits@sling.apache.org" <co...@sling.apache.org>.