Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
org.apache.jackrabbit.oak.security.authorization.permission.PermissionStoreEditor Maven / Gradle / Ivy
/*
* 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.jackrabbit.oak.security.authorization.permission;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import javax.annotation.Nonnull;
import com.google.common.base.Objects;
import com.google.common.base.Strings;
import com.google.common.collect.Maps;
import com.google.common.primitives.Longs;
import org.apache.jackrabbit.oak.api.PropertyState;
import org.apache.jackrabbit.oak.api.Type;
import org.apache.jackrabbit.oak.plugins.memory.PropertyStates;
import org.apache.jackrabbit.oak.plugins.nodetype.TypePredicate;
import org.apache.jackrabbit.oak.plugins.tree.TreeFactory;
import org.apache.jackrabbit.oak.spi.security.authorization.accesscontrol.AccessControlConstants;
import org.apache.jackrabbit.oak.spi.security.authorization.permission.PermissionConstants;
import org.apache.jackrabbit.oak.spi.security.authorization.restriction.Restriction;
import org.apache.jackrabbit.oak.spi.security.authorization.restriction.RestrictionProvider;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBits;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeBitsProvider;
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeConstants;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.util.Text;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import static com.google.common.collect.Iterables.addAll;
import static com.google.common.collect.Sets.newLinkedHashSet;
import static org.apache.jackrabbit.JcrConstants.JCR_PRIMARYTYPE;
import static org.apache.jackrabbit.oak.plugins.tree.impl.TreeConstants.OAK_CHILD_ORDER;
final class PermissionStoreEditor implements AccessControlConstants, PermissionConstants {
private static final Logger log = LoggerFactory.getLogger(PermissionStoreEditor.class);
private final String accessControlledPath;
private final String nodeName;
private final Map> entries = Maps.newHashMap();
private final NodeBuilder permissionRoot;
PermissionStoreEditor(@Nonnull String aclPath, @Nonnull String name,
@Nonnull NodeState node, @Nonnull NodeBuilder permissionRoot,
@Nonnull TypePredicate isACE, @Nonnull TypePredicate isGrantACE,
@Nonnull PrivilegeBitsProvider bitsProvider,
@Nonnull RestrictionProvider restrictionProvider) {
this.permissionRoot = permissionRoot;
if (name.equals(REP_REPO_POLICY)) {
accessControlledPath = "";
} else {
accessControlledPath = aclPath.isEmpty() ? "/" : aclPath;
}
nodeName = PermissionUtil.getEntryName(accessControlledPath);
Set orderedChildNames = newLinkedHashSet(node.getNames(OAK_CHILD_ORDER));
long n = orderedChildNames.size();
if (node.getChildNodeCount(n + 1) > n) {
addAll(orderedChildNames, node.getChildNodeNames());
}
PrivilegeBits jcrAll = bitsProvider.getBits(PrivilegeConstants.JCR_ALL);
int index = 0;
for (String childName : orderedChildNames) {
NodeState ace = node.getChildNode(childName);
if (isACE.apply(ace)) {
boolean isAllow = isGrantACE.apply(ace);
PrivilegeBits privilegeBits = bitsProvider.getBits(ace.getNames(REP_PRIVILEGES));
Set restrictions = restrictionProvider.readRestrictions(Strings.emptyToNull(accessControlledPath), TreeFactory.createReadOnlyTree(ace));
AcEntry entry = (privilegeBits.equals(jcrAll)) ?
new JcrAllAcEntry(ace, accessControlledPath, index, isAllow, privilegeBits, restrictions) :
new AcEntry(ace, accessControlledPath, index, isAllow, privilegeBits, restrictions);
List list = entries.get(entry.principalName);
if (list == null) {
list = new ArrayList();
entries.put(entry.principalName, list);
}
list.add(entry);
index++;
}
}
}
String getPath() {
return accessControlledPath;
}
boolean isEmpty() {
return entries.isEmpty();
}
void removePermissionEntries(PermissionStoreEditor otherEditor) {
entries.keySet().removeAll(otherEditor.entries.keySet());
}
void removePermissionEntries() {
for (String principalName : entries.keySet()) {
if (permissionRoot.hasChildNode(principalName)) {
NodeBuilder principalRoot = permissionRoot.getChildNode(principalName);
// find the ACL node that for this path and principal
NodeBuilder parent = principalRoot.getChildNode(nodeName);
if (!parent.exists()) {
continue;
}
// check if the node is the correct one
if (PermissionUtil.checkACLPath(parent, accessControlledPath)) {
// remove and reconnect child nodes
NodeBuilder newParent = null;
for (String childName : parent.getChildNodeNames()) {
if (childName.charAt(0) != 'c') {
continue;
}
NodeBuilder child = parent.getChildNode(childName);
if (newParent == null) {
newParent = child;
} else {
newParent.setChildNode(childName, child.getNodeState());
child.remove();
}
}
parent.remove();
if (newParent != null) {
principalRoot.setChildNode(nodeName, newParent.getNodeState());
}
} else {
// check if any of the child nodes match
for (String childName : parent.getChildNodeNames()) {
if (childName.charAt(0) != 'c') {
continue;
}
NodeBuilder child = parent.getChildNode(childName);
if (PermissionUtil.checkACLPath(child, accessControlledPath)) {
child.remove();
}
}
}
} else {
log.error("Unable to remove permission entry {}: Principal root missing.", this);
}
}
}
void updatePermissionEntries() {
for (Map.Entry> entry: entries.entrySet()) {
String principalName = entry.getKey();
NodeBuilder principalRoot = permissionRoot.child(principalName);
if (!principalRoot.hasProperty(JCR_PRIMARYTYPE)) {
principalRoot.setProperty(JCR_PRIMARYTYPE, NT_REP_PERMISSION_STORE, Type.NAME);
}
NodeBuilder parent = principalRoot.child(nodeName);
if (!parent.hasProperty(JCR_PRIMARYTYPE)) {
parent.setProperty(JCR_PRIMARYTYPE, NT_REP_PERMISSION_STORE, Type.NAME);
}
// check if current parent already has the correct path
if (parent.hasProperty(REP_ACCESS_CONTROLLED_PATH)) {
if (!PermissionUtil.checkACLPath(parent, accessControlledPath)) {
// hash collision, find a new child
NodeBuilder child = null;
int idx = 0;
for (String childName : parent.getChildNodeNames()) {
if (childName.charAt(0) != 'c') {
continue;
}
child = parent.getChildNode(childName);
if (PermissionUtil.checkACLPath(child, accessControlledPath)) {
break;
}
child = null;
idx++;
}
while (child == null) {
String name = 'c' + String.valueOf(idx++);
child = parent.getChildNode(name);
if (child.exists()) {
child = null;
} else {
child = parent.child(name);
child.setProperty(JCR_PRIMARYTYPE, NT_REP_PERMISSION_STORE, Type.NAME);
}
}
parent = child;
parent.setProperty(REP_ACCESS_CONTROLLED_PATH, accessControlledPath);
}
} else {
// new parent
parent.setProperty(REP_ACCESS_CONTROLLED_PATH, accessControlledPath);
}
updateEntries(parent, entry.getValue());
}
}
private void updateEntries(NodeBuilder parent, List list) {
// remove old entries
for (String childName : parent.getChildNodeNames()) {
if (childName.charAt(0) != 'c') {
parent.getChildNode(childName).remove();
}
}
for (AcEntry ace: list) {
ace.writeToPermissionStore(parent);
}
}
private final class JcrAllAcEntry extends AcEntry {
private JcrAllAcEntry(@Nonnull NodeState node,
@Nonnull String accessControlledPath,
int index, boolean isAllow,
@Nonnull PrivilegeBits privilegeBits,
@Nonnull Set restrictions) {
super(node, accessControlledPath, index, isAllow, privilegeBits, restrictions);
}
@Override
protected PropertyState getPrivilegeBitsProperty() {
return PropertyStates.createProperty(REP_PRIVILEGE_BITS, Longs.asList(PermissionStore.DYNAMIC_ALL_BITS), Type.LONGS);
}
}
private class AcEntry {
private final String accessControlledPath;
private final String principalName;
private final PrivilegeBits privilegeBits;
private final boolean isAllow;
private final Set restrictions;
private final int index;
private int hashCode = -1;
private AcEntry(@Nonnull NodeState node, @Nonnull String accessControlledPath, int index,
boolean isAllow, @Nonnull PrivilegeBits privilegeBits,
@Nonnull Set restrictions) {
this.accessControlledPath = accessControlledPath;
this.index = index;
this.principalName = Text.escapeIllegalJcrChars(node.getString(REP_PRINCIPAL_NAME));
this.privilegeBits = privilegeBits;
this.isAllow = isAllow;
this.restrictions = restrictions;
}
private void writeToPermissionStore(NodeBuilder parent) {
NodeBuilder n = parent.child(String.valueOf(index))
.setProperty(JCR_PRIMARYTYPE, NT_REP_PERMISSIONS, Type.NAME)
.setProperty(REP_IS_ALLOW, isAllow)
.setProperty(getPrivilegeBitsProperty());
for (Restriction restriction : restrictions) {
n.setProperty(restriction.getProperty());
}
}
protected PropertyState getPrivilegeBitsProperty() {
return privilegeBits.asPropertyState(REP_PRIVILEGE_BITS);
}
//-------------------------------------------------------------< Object >---
@Override
public int hashCode() {
if (hashCode == -1) {
hashCode = Objects.hashCode(accessControlledPath, principalName, privilegeBits, isAllow, restrictions);
}
return hashCode;
}
@Override
public boolean equals(Object o) {
if (o == this) {
return true;
}
if (o instanceof AcEntry) {
AcEntry other = (AcEntry) o;
return isAllow == other.isAllow
&& privilegeBits.equals(other.privilegeBits)
&& principalName.equals(other.principalName)
&& accessControlledPath.equals(other.accessControlledPath)
&& restrictions.equals(other.restrictions);
}
return false;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append(accessControlledPath);
sb.append(';').append(principalName);
sb.append(';').append(isAllow ? "allow" : "deny");
sb.append(';').append(privilegeBits);
sb.append(';').append(restrictions);
return sb.toString();
}
}
}