blob: c387b8c1ca3fec17880d973cce9195d78714f78c [file] [log] [blame]
/*
* 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.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import javax.jcr.Item;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
import javax.servlet.Servlet;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Properties;
import org.apache.felix.scr.annotations.Property;
import org.apache.felix.scr.annotations.Service;
import org.apache.jackrabbit.api.security.principal.PrincipalManager;
import org.apache.sling.api.SlingHttpServletRequest;
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.jcr.jackrabbit.accessmanager.ModifyAce;
import org.apache.sling.servlets.post.Modification;
/**
* <p>
* Sling Post Servlet implementation for modifying the ACEs for a principal on a JCR
* resource.
* </p>
* <h2>Rest Service Description</h2>
* <p>
* Modify a principal's ACEs for the node identified as a resource by the request
* URL &gt;resource&lt;.modifyAce.html
* </p>
* <h4>Methods</h4>
* <ul>
* <li>POST</li>
* </ul>
* <h4>Post Parameters</h4>
* <dl>
* <dt>principalId</dt>
* <dd>The principal of the ACEs to modify in the ACL specified by the path.</dd>
* <dt>privilege@*</dt>
* <dd>One or more privileges, either granted or denied or none, which will be applied
* to (or removed from) the node ACL. Any permissions that are present in an
* existing ACE for the principal but not in the request are left untouched.</dd>
* </dl>
*
* <h4>Response</h4>
* <dl>
* <dt>200</dt>
* <dd>Success.</dd>
* <dt>404</dt>
* <dd>The resource was not found.</dd>
* <dt>500</dt>
* <dd>Failure. HTML explains the failure.</dd>
* </dl>
*
* <h4>Notes</h4>
* <p>
* The principalId is assumed to refer directly to an Authorizable, that comes direct from
* the UserManager. This can be a group or a user, but if its a group, denied permissions
* will not be added to the group. The group will only contain granted privileges.
* </p>
*/
@Component (immediate=true,
label="%modifyAce.post.operation.name",
description="%modifyAce.post.operation.description"
)
@Service (value={
Servlet.class,
ModifyAce.class
})
@Properties ({
@Property (name="sling.servlet.resourceTypes",
value="sling/servlet/default"),
@Property (name="sling.servlet.methods",
value="POST"),
@Property (name="sling.servlet.selectors",
value="modifyAce")
})
public class ModifyAceServlet extends AbstractAccessPostServlet implements ModifyAce {
private static final long serialVersionUID = -9182485466670280437L;
/* (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 {
Session session = request.getResourceResolver().adaptTo(Session.class);
String resourcePath = request.getResource().getPath();
String principalId = request.getParameter("principalId");
Map<String, String> privileges = new HashMap<String, 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 privilegeName = paramName.substring(10);
String parameterValue = request.getParameter(paramName);
privileges.put(privilegeName, parameterValue);
}
}
}
String order = request.getParameter("order");
modifyAce(session, resourcePath, principalId, privileges, order);
}
/* (non-Javadoc)
* @see org.apache.sling.jcr.jackrabbit.accessmanager.ModifyAce#modifyAce(javax.jcr.Session, java.lang.String, java.lang.String, java.util.Map, java.lang.String)
*/
public void modifyAce(Session jcrSession, String resourcePath,
String principalId, Map<String, String> privileges, String order)
throws RepositoryException {
if (jcrSession == null) {
throw new RepositoryException("JCR Session not found");
}
if (principalId == null) {
throw new RepositoryException("principalId was not submitted.");
}
PrincipalManager principalManager = AccessControlUtil.getPrincipalManager(jcrSession);
Principal principal = principalManager.getPrincipal(principalId);
if (resourcePath == null) {
throw new ResourceNotFoundException("Resource path was not supplied.");
}
Item item = jcrSession.getItem(resourcePath);
if (item != null) {
resourcePath = item.getPath();
} else {
throw new ResourceNotFoundException("Resource is not a JCR Node");
}
// Collect the modified privileges from the request.
Set<String> grantedPrivilegeNames = new HashSet<String>();
Set<String> deniedPrivilegeNames = new HashSet<String>();
Set<String> removedPrivilegeNames = new HashSet<String>();
Set<Entry<String, String>> entrySet = privileges.entrySet();
for (Entry<String, String> entry : entrySet) {
String privilegeName = entry.getKey();
if (privilegeName.startsWith("privilege@")) {
privilegeName = privilegeName.substring(10);
}
String parameterValue = entry.getValue();
if (parameterValue != null && parameterValue.length() > 0) {
if ("granted".equals(parameterValue)) {
grantedPrivilegeNames.add(privilegeName);
} else if ("denied".equals(parameterValue)) {
deniedPrivilegeNames.add(privilegeName);
} else if ("none".equals(parameterValue)){
removedPrivilegeNames.add(privilegeName);
}
}
}
// Make the actual changes.
try {
AccessControlUtil.replaceAccessControlEntry(jcrSession, resourcePath, principal,
grantedPrivilegeNames.toArray(new String[grantedPrivilegeNames.size()]),
deniedPrivilegeNames.toArray(new String[deniedPrivilegeNames.size()]),
removedPrivilegeNames.toArray(new String[removedPrivilegeNames.size()]),
order);
if (jcrSession.hasPendingChanges()) {
jcrSession.save();
}
} catch (RepositoryException re) {
throw new RepositoryException("Failed to create ace.", re);
}
}
}