You are viewing a plain text version of this content. The canonical link for it is here.
Posted to oak-commits@jackrabbit.apache.org by an...@apache.org on 2013/02/13 16:19:34 UTC
svn commit: r1445660 [1/2] - in /jackrabbit/oak/trunk/oak-core/src:
main/java/org/apache/jackrabbit/oak/security/privilege/
main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/
test/java/org/apache/jackrabbit/oak/security/privilege/
Author: angela
Date: Wed Feb 13 15:19:34 2013
New Revision: 1445660
URL: http://svn.apache.org/r1445660
Log:
OAK-527: permissions (wip)
OAK-64: privilege mgt (wip)
Added:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeBits.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionStore.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/privilege/
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeBitsTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionStoreTest.java
jackrabbit/oak/trunk/oak-core/src/test/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidatorTest.java
Removed:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionReader.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionWriter.java
Modified:
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/JcrAllCommitHook.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConstants.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeInitializer.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeManagerImpl.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeMigrator.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidator.java
jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidatorProvider.java
jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/JcrAllCommitHook.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/JcrAllCommitHook.java?rev=1445660&r1=1445659&r2=1445660&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/JcrAllCommitHook.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/JcrAllCommitHook.java Wed Feb 13 15:19:34 2013
@@ -73,6 +73,14 @@ public class JcrAllCommitHook implements
propertyBuilder.addValue(name);
jcrAll.setProperty(propertyBuilder.getPropertyState());
}
+
+ // update the privilege bits of the jcr:all in case the new
+ // privilege isn't an aggregate
+ if (after.getProperty(REP_AGGREGATES) == null) {
+ PrivilegeBits bits = PrivilegeBits.getInstance(after.getProperty(REP_BITS));
+ PrivilegeBits all = PrivilegeBits.getInstance(jcrAll.getProperty(REP_BITS));
+ PrivilegeBits.getInstance(all).add(bits).writeTo(jcrAll, JCR_ALL);
+ }
}
}
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeBits.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeBits.java?rev=1445660&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeBits.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeBits.java Wed Feb 13 15:19:34 2013
@@ -0,0 +1,770 @@
+/*
+ * 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.privilege;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import com.google.common.primitives.Longs;
+import org.apache.jackrabbit.oak.api.PropertyState;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.api.Type;
+import org.apache.jackrabbit.oak.spi.security.authorization.Permissions;
+import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+/**
+ * {@code PrivilegeBits} TODO
+ */
+public final class PrivilegeBits implements PrivilegeConstants {
+
+ private static final long NO_PRIVILEGE = 0;
+ private static final long READ_NODES = 1;
+ private static final long READ_PROPERTIES = READ_NODES << 1;
+ private static final long ADD_PROPERTIES = READ_PROPERTIES << 1;
+ private static final long ALTER_PROPERTIES = ADD_PROPERTIES << 1;
+ private static final long REMOVE_PROPERTIES = ALTER_PROPERTIES << 1;
+ private static final long ADD_CHILD_NODES = REMOVE_PROPERTIES << 1;
+ private static final long REMOVE_CHILD_NODES = ADD_CHILD_NODES << 1;
+ private static final long REMOVE_NODE = REMOVE_CHILD_NODES << 1;
+ private static final long READ_AC = REMOVE_NODE << 1;
+ private static final long MODIFY_AC = READ_AC << 1;
+ private static final long NODE_TYPE_MNGMT = MODIFY_AC << 1;
+ private static final long VERSION_MNGMT = NODE_TYPE_MNGMT << 1;
+ private static final long LOCK_MNGMT = VERSION_MNGMT << 1;
+ private static final long LIFECYCLE_MNGMT = LOCK_MNGMT << 1;
+ private static final long RETENTION_MNGMT = LIFECYCLE_MNGMT << 1;
+ private static final long WORKSPACE_MNGMT = RETENTION_MNGMT << 1;
+ private static final long NODE_TYPE_DEF_MNGMT = WORKSPACE_MNGMT << 1;
+ private static final long NAMESPACE_MNGMT = NODE_TYPE_DEF_MNGMT << 1;
+ private static final long PRIVILEGE_MNGMT = NAMESPACE_MNGMT << 1;
+ private static final long USER_MNGMT = PRIVILEGE_MNGMT << 1;
+
+ private static final long READ = READ_NODES | READ_PROPERTIES;
+ private static final long MODIFY_PROPERTIES = ADD_PROPERTIES | ALTER_PROPERTIES | REMOVE_PROPERTIES;
+ private static final long WRITE = MODIFY_PROPERTIES | ADD_CHILD_NODES | REMOVE_CHILD_NODES | REMOVE_NODE;
+ private static final long WRITE2 = WRITE | NODE_TYPE_MNGMT;
+
+ public static final PrivilegeBits EMPTY = new PrivilegeBits(UnmodifiableData.EMPTY);
+
+ static final Map<String, PrivilegeBits> BUILT_IN = new HashMap<String, PrivilegeBits>();
+
+ static {
+ BUILT_IN.put(REP_READ_NODES, getInstance(READ_NODES));
+ BUILT_IN.put(REP_READ_PROPERTIES, getInstance(READ_PROPERTIES));
+ BUILT_IN.put(REP_ADD_PROPERTIES, getInstance(ADD_PROPERTIES));
+ BUILT_IN.put(REP_ALTER_PROPERTIES, getInstance(ALTER_PROPERTIES));
+ BUILT_IN.put(REP_REMOVE_PROPERTIES, getInstance(REMOVE_PROPERTIES));
+ BUILT_IN.put(JCR_ADD_CHILD_NODES, getInstance(ADD_CHILD_NODES));
+ BUILT_IN.put(JCR_REMOVE_CHILD_NODES, getInstance(REMOVE_CHILD_NODES));
+ BUILT_IN.put(JCR_REMOVE_NODE, getInstance(REMOVE_NODE));
+ BUILT_IN.put(JCR_READ_ACCESS_CONTROL, getInstance(READ_AC));
+ BUILT_IN.put(JCR_MODIFY_ACCESS_CONTROL, getInstance(MODIFY_AC));
+ BUILT_IN.put(JCR_NODE_TYPE_MANAGEMENT, getInstance(NODE_TYPE_MNGMT));
+ BUILT_IN.put(JCR_VERSION_MANAGEMENT, getInstance(VERSION_MNGMT));
+ BUILT_IN.put(JCR_LOCK_MANAGEMENT, getInstance(LOCK_MNGMT));
+ BUILT_IN.put(JCR_LIFECYCLE_MANAGEMENT, getInstance(LIFECYCLE_MNGMT));
+ BUILT_IN.put(JCR_RETENTION_MANAGEMENT, getInstance(RETENTION_MNGMT));
+ BUILT_IN.put(JCR_WORKSPACE_MANAGEMENT, getInstance(WORKSPACE_MNGMT));
+ BUILT_IN.put(JCR_NODE_TYPE_DEFINITION_MANAGEMENT, getInstance(NODE_TYPE_DEF_MNGMT));
+ BUILT_IN.put(JCR_NAMESPACE_MANAGEMENT, getInstance(NAMESPACE_MNGMT));
+ BUILT_IN.put(REP_PRIVILEGE_MANAGEMENT, getInstance(PRIVILEGE_MNGMT));
+ BUILT_IN.put(REP_USER_MANAGEMENT, getInstance(USER_MNGMT));
+
+ BUILT_IN.put(JCR_READ, PrivilegeBits.getInstance(READ));
+ BUILT_IN.put(JCR_MODIFY_PROPERTIES, PrivilegeBits.getInstance(MODIFY_PROPERTIES));
+ BUILT_IN.put(JCR_WRITE, PrivilegeBits.getInstance(WRITE));
+ BUILT_IN.put(REP_WRITE, PrivilegeBits.getInstance(WRITE2));
+ }
+
+ private final Data d;
+
+ /**
+ * Private constructor.
+ *
+ * @param d
+ */
+ private PrivilegeBits(Data d) {
+ this.d = d;
+ }
+
+ /**
+ * Creates a mutable instance of privilege bits.
+ *
+ * @return a new instance of privilege bits.
+ */
+ public static PrivilegeBits getInstance() {
+ return new PrivilegeBits(new ModifiableData());
+ }
+
+ /**
+ * Creates a mutable instance of privilege bits.
+ *
+ * @param base
+ * @return a new instance of privilege bits.
+ */
+ public static PrivilegeBits getInstance(PrivilegeBits base) {
+ return new PrivilegeBits(new ModifiableData(base.d));
+ }
+
+ /**
+ * Get or create an instance of privilege bits for a specific property that
+ * stores privileges.
+ *
+ * @param property
+ * @return an instance of {@code PrivilegeBits}
+ */
+ public static PrivilegeBits getInstance(PropertyState property) {
+ if (property == null) {
+ return EMPTY;
+ }
+
+ List<Long> vs = (List<Long>) property.getValue(Type.LONGS);
+ if (vs.size() == 1) {
+ return getInstance(vs.get(0));
+ } else {
+ return getInstance(Longs.toArray(vs));
+ }
+ }
+
+ /**
+ * Get or create an instance of privilege bits for a privilege definition.
+ *
+ * @param tree A privilege definition tree or the privileges root.
+ * @return an instance of {@code PrivilegeBits}
+ */
+ public static PrivilegeBits getInstance(Tree tree) {
+ if (tree == null) {
+ return EMPTY;
+ }
+ String privName = tree.getName();
+ if (BUILT_IN.containsKey(privName)) {
+ return BUILT_IN.get(privName);
+ } else if (REP_PRIVILEGES.equals(privName)) {
+ return getInstance(tree.getProperty(REP_NEXT));
+ } else {
+ return getInstance(tree.getProperty(REP_BITS));
+ }
+ }
+
+ /**
+ * Internal method to get or create an instance of privilege bits for the
+ * specified long value.
+ *
+ * @param bits
+ * @return an instance of {@code PrivilegeBits}
+ */
+ private static PrivilegeBits getInstance(long bits) {
+ if (bits == NO_PRIVILEGE) {
+ return EMPTY;
+ } else {
+ checkArgument(bits > NO_PRIVILEGE);
+ return new PrivilegeBits(new UnmodifiableData(bits));
+ }
+ }
+
+
+ /**
+ * Internal method to create a new instance of {@code PrivilegeBits}.
+ *
+ * @param bits
+ * @return an instance of {@code PrivilegeBits}
+ */
+ private static PrivilegeBits getInstance(long[] bits) {
+ return new PrivilegeBits(new UnmodifiableData(bits));
+ }
+
+ /**
+ * TODO
+ *
+ * @param bits
+ * @param parentBits
+ * @param isAllow
+ * @return
+ */
+ public static long calculatePermissions(PrivilegeBits bits, PrivilegeBits parentBits, boolean isAllow) {
+ long privs = bits.d.longValue();
+ long parentPrivs = parentBits.d.longValue();
+ long perm = Permissions.NO_PERMISSION;
+ if ((privs & READ) == READ) {
+ perm |= Permissions.READ;
+ } else {
+ if ((privs & READ_NODES) == READ_NODES) {
+ perm |= Permissions.READ_NODE;
+ } else if (((privs & READ_PROPERTIES) == READ_PROPERTIES)) {
+ perm |= Permissions.READ_PROPERTY;
+ }
+ }
+ if ((privs & MODIFY_PROPERTIES) == MODIFY_PROPERTIES) {
+ perm |= Permissions.SET_PROPERTY;
+ } else {
+ if ((privs & ADD_PROPERTIES) == ADD_PROPERTIES) {
+ perm |= Permissions.ADD_PROPERTY;
+ } else if ((privs & MODIFY_PROPERTIES) == MODIFY_PROPERTIES) {
+ perm |= Permissions.MODIFY_PROPERTY;
+ } else if ((privs & REMOVE_PROPERTIES) == REMOVE_PROPERTIES) {
+ perm |= Permissions.REMOVE_PROPERTY;
+ }
+ }
+
+ // add_node permission is granted through privilege on the parent.
+ if ((parentPrivs & ADD_CHILD_NODES) == ADD_CHILD_NODES) {
+ perm |= Permissions.ADD_NODE;
+ }
+
+ /*
+ remove_node is
+ allowed: only if remove_child_nodes privilege is present on
+ the parent AND remove_node is present on the node itself
+ denied : if either remove_child_nodes is denied on the parent
+ OR remove_node is denied on the node itself.
+ */
+ if (isAllow) {
+ if ((parentPrivs & REMOVE_CHILD_NODES) == REMOVE_CHILD_NODES &&
+ (privs & REMOVE_NODE) == REMOVE_NODE) {
+ perm |= Permissions.REMOVE_NODE;
+ }
+ } else {
+ if ((parentPrivs & REMOVE_CHILD_NODES) == REMOVE_CHILD_NODES ||
+ (privs & REMOVE_NODE) == REMOVE_NODE) {
+ perm |= Permissions.REMOVE_NODE;
+ }
+ }
+
+ // modify_child_node_collection permission is granted through
+ // privileges on the parent
+ if ((parentPrivs & ADD_CHILD_NODES) == ADD_CHILD_NODES &&
+ (parentPrivs & REMOVE_CHILD_NODES) == REMOVE_CHILD_NODES) {
+ perm |= Permissions.MODIFY_CHILD_NODE_COLLECTION;
+ }
+
+ // the remaining (special) permissions are simply defined on the node
+ if ((privs & READ_AC) == READ_AC) {
+ perm |= Permissions.READ_ACCESS_CONTROL;
+ }
+ if ((privs & MODIFY_AC) == MODIFY_AC) {
+ perm |= Permissions.MODIFY_ACCESS_CONTROL;
+ }
+ if ((privs & LIFECYCLE_MNGMT) == LIFECYCLE_MNGMT) {
+ perm |= Permissions.LIFECYCLE_MANAGEMENT;
+ }
+ if ((privs & LOCK_MNGMT) == LOCK_MNGMT) {
+ perm |= Permissions.LOCK_MANAGEMENT;
+ }
+ if ((privs & NODE_TYPE_MNGMT) == NODE_TYPE_MNGMT) {
+ perm |= Permissions.NODE_TYPE_MANAGEMENT;
+ }
+ if ((privs & RETENTION_MNGMT) == RETENTION_MNGMT) {
+ perm |= Permissions.RETENTION_MANAGEMENT;
+ }
+ if ((privs & VERSION_MNGMT) == VERSION_MNGMT) {
+ perm |= Permissions.VERSION_MANAGEMENT;
+ }
+ if ((privs & WORKSPACE_MNGMT) == WORKSPACE_MNGMT) {
+ perm |= Permissions.WORKSPACE_MANAGEMENT;
+ }
+ if ((privs & NODE_TYPE_DEF_MNGMT) == NODE_TYPE_DEF_MNGMT) {
+ perm |= Permissions.NODE_TYPE_DEFINITION_MANAGEMENT;
+ }
+ if ((privs & NAMESPACE_MNGMT) == NAMESPACE_MNGMT) {
+ perm |= Permissions.NAMESPACE_MANAGEMENT;
+ }
+ if ((privs & PRIVILEGE_MNGMT) == PRIVILEGE_MNGMT) {
+ perm |= Permissions.PRIVILEGE_MANAGEMENT;
+ }
+ if ((privs & USER_MNGMT) == USER_MNGMT) {
+ perm |= Permissions.USER_MANAGEMENT;
+ }
+ return perm;
+ }
+
+ /**
+ * Returns {@code true} if this privilege bits includes no privileges
+ * at all.
+ *
+ * @return {@code true} if this privilege bits includes no privileges
+ * at all; {@code false} otherwise.
+ * @see Permissions#NO_PERMISSION
+ */
+ public boolean isEmpty() {
+ return d.isEmpty();
+ }
+
+ /**
+ * Returns an unmodifiable instance.
+ *
+ * @return an unmodifiable {@code PrivilegeBits} instance.
+ */
+ public PrivilegeBits unmodifiable() {
+ if (d instanceof ModifiableData) {
+ if (d.isSimple()) {
+ return getInstance(d.longValue());
+ } else {
+ long[] bits = d.longValues();
+ long[] copy = new long[bits.length];
+ System.arraycopy(bits, 0, copy, 0, bits.length);
+ return getInstance(copy);
+ }
+ } else {
+ return this;
+ }
+ }
+
+ /**
+ * Returns {@code true} if all privileges defined by the specified
+ * {@code otherBits} are present in this instance.
+ *
+ * @param otherBits
+ * @return {@code true} if all privileges defined by the specified
+ * {@code otherBits} are included in this instance; {@code false}
+ * otherwise.
+ */
+ public boolean includes(PrivilegeBits otherBits) {
+ return d.includes(otherBits.d);
+ }
+
+ /**
+ * Returns {@code true} if this instance includes the jcr:read
+ * privilege. Shortcut for calling {@link PrivilegeBits#includes(PrivilegeBits)}
+ * where the other bits represented the jcr:read privilege.
+ *
+ * @return {@code true} if this instance includes the jcr:read
+ * privilege; {@code false} otherwise.
+ */
+ public boolean includesRead(long readPermission) {
+ if (this == EMPTY) {
+ return false;
+ } else {
+ return d.includes(readPermission);
+ }
+ }
+
+ /**
+ * Adds the other privilege bits to this instance.
+ *
+ * @param other The other privilege bits to be added.
+ * @return The updated instance.
+ * @throws UnsupportedOperationException if this instance is immutable.
+ */
+ public PrivilegeBits add(PrivilegeBits other) {
+ if (d instanceof ModifiableData) {
+ ((ModifiableData) d).add(other.d);
+ return this;
+ } else {
+ throw new UnsupportedOperationException("immutable privilege bits");
+ }
+ }
+
+ /**
+ * Subtracts the other PrivilegeBits from the this.<br>
+ * If the specified bits do not intersect with this, it isn't modified.<br>
+ * If {@code this} is included in {@code other} {@link #EMPTY empty}
+ * privilege bits is returned.
+ *
+ * @param other The other privilege bits to be substracted from this instance.
+ * @return The updated instance.
+ * @throws UnsupportedOperationException if this instance is immutable.
+ */
+ public PrivilegeBits diff(PrivilegeBits other) {
+ if (d instanceof ModifiableData) {
+ ((ModifiableData) d).diff(other.d);
+ return this;
+ } else {
+ throw new UnsupportedOperationException("immutable privilege bits");
+ }
+ }
+
+ /**
+ * Subtracts the {@code b} from {@code a} and adds the result (diff)
+ * to this instance.
+ *
+ * @param a An instance of privilege bits.
+ * @param b An instance of privilege bits.
+ * @return The updated instance.
+ * @throws UnsupportedOperationException if this instance is immutable.
+ */
+ public PrivilegeBits addDifference(PrivilegeBits a, PrivilegeBits b) {
+ if (d instanceof ModifiableData) {
+ ((ModifiableData) d).addDifference(a.d, b.d);
+ return this;
+ } else {
+ throw new UnsupportedOperationException("immutable privilege bits");
+ }
+ }
+
+ /**
+ * Package private method to calculate the privilege bits associated with a
+ * given built-in or custom privilege definition.
+ *
+ * @return an instance of {@code PrivilegeBits}
+ */
+ PrivilegeBits nextBits() {
+ if (this == EMPTY) {
+ return EMPTY;
+ } else {
+ return new PrivilegeBits(d.next());
+ }
+ }
+
+ void writeTo(Tree tree) {
+ String name = (REP_PRIVILEGES.equals(tree.getName())) ? REP_NEXT : REP_BITS;
+ tree.setProperty(name, Longs.asList(d.longValues()), Type.LONGS);
+ }
+
+ void writeTo(NodeBuilder nodeBuilder, String nodeName) {
+ String name = (REP_PRIVILEGES.equals(nodeName)) ? REP_NEXT : REP_BITS;
+ nodeBuilder.setProperty(name, Longs.asList(d.longValues()), Type.LONGS);
+ }
+
+ //-------------------------------------------------------------< Object >---
+ @Override
+ public int hashCode() {
+ return d.hashCode();
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ } else if (o instanceof PrivilegeBits) {
+ return d.equals(((PrivilegeBits) o).d);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public String toString() {
+ StringBuilder sb = new StringBuilder("PrivilegeBits: ");
+ if (d.isSimple()) {
+ sb.append(d.longValue());
+ } else {
+ sb.append(Arrays.toString(d.longValues()));
+ }
+ return sb.toString();
+ }
+
+ //------------------------------------------------------< inner classes >---
+
+ /**
+ * Base class for the internal privilege bits representation and handling.
+ */
+ private static abstract class Data {
+
+ abstract boolean isEmpty();
+
+ abstract long longValue();
+
+ abstract long[] longValues();
+
+ abstract boolean isSimple();
+
+ abstract Data next();
+
+ abstract boolean includes(Data other);
+
+ abstract boolean includes(long permissions);
+
+ static boolean includes(long bits, long otherBits) {
+ return (bits | ~otherBits) == -1;
+ }
+
+ static boolean includes(long[] bits, long[] otherBits) {
+ if (otherBits.length <= bits.length) {
+ // test for each long if is included
+ for (int i = 0; i < otherBits.length; i++) {
+ if ((bits[i] | ~otherBits[i]) != -1) {
+ return false;
+ }
+ }
+ return true;
+ } else {
+ // otherbits array is longer > cannot be included in bits
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Immutable Data object
+ */
+ private static class UnmodifiableData extends Data {
+
+ private static final long MAX = Long.MAX_VALUE / 2;
+
+ private static final UnmodifiableData EMPTY = new UnmodifiableData(NO_PRIVILEGE);
+
+ private final long bits;
+ private final long[] bitsArr;
+ private final boolean isSimple;
+
+ private UnmodifiableData(long bits) {
+ this.bits = bits;
+ bitsArr = new long[]{bits};
+ isSimple = true;
+ }
+
+ private UnmodifiableData(long[] bitsArr) {
+ bits = NO_PRIVILEGE;
+ this.bitsArr = bitsArr;
+ isSimple = false;
+ }
+
+ @Override
+ boolean isEmpty() {
+ return this == EMPTY;
+ }
+
+ @Override
+ long longValue() {
+ return bits;
+ }
+
+ @Override
+ long[] longValues() {
+ return bitsArr;
+ }
+
+ @Override
+ boolean isSimple() {
+ return isSimple;
+ }
+
+ @Override
+ Data next() {
+ if (this == EMPTY) {
+ return EMPTY;
+ } else if (isSimple) {
+ if (bits < MAX) {
+ long b = bits << 1;
+ return new UnmodifiableData(b);
+ } else {
+ return new UnmodifiableData(new long[]{bits}).next();
+ }
+ } else {
+ long[] bts;
+ long last = bitsArr[bitsArr.length - 1];
+ if (last < MAX) {
+ bts = new long[bitsArr.length];
+ System.arraycopy(bitsArr, 0, bts, 0, bitsArr.length);
+ bts[bts.length - 1] = last << 1;
+ } else {
+ bts = new long[bitsArr.length + 1];
+ bts[bts.length - 1] = 1;
+ }
+ return new UnmodifiableData(bts);
+ }
+ }
+
+ @Override
+ boolean includes(Data other) {
+ if (isSimple) {
+ return (other.isSimple()) && includes(bits, other.longValue());
+ } else {
+ return includes(bitsArr, other.longValues());
+ }
+ }
+
+ @Override
+ boolean includes(long permissions) {
+ return (isSimple) ? (bits & permissions) == permissions : (bitsArr[0] & permissions) == permissions;
+ }
+
+ //---------------------------------------------------------< Object >---
+ @Override
+ public int hashCode() {
+ return (isSimple) ? new Long(bits).hashCode() : Arrays.hashCode(bitsArr);
+ }
+
+ @Override
+ public boolean equals(Object o) {
+ if (o == this) {
+ return true;
+ } else if (o instanceof UnmodifiableData) {
+ UnmodifiableData d = (UnmodifiableData) o;
+ if (isSimple != d.isSimple) {
+ return false;
+ }
+ if (isSimple) {
+ return bits == d.bits;
+ } else {
+ return Arrays.equals(bitsArr, d.bitsArr);
+ }
+ } else {
+ return false;
+ }
+ }
+ }
+
+ /**
+ * Mutable implementation of the Data base class.
+ */
+ private static class ModifiableData extends Data {
+
+ private long[] bits;
+
+ private ModifiableData() {
+ bits = new long[]{NO_PRIVILEGE};
+ }
+
+ private ModifiableData(Data base) {
+ long[] b = base.longValues();
+ switch (b.length) {
+ case 0:
+ // empty
+ bits = new long[]{NO_PRIVILEGE};
+ break;
+ case 1:
+ // single long
+ bits = new long[]{b[0]};
+ break;
+ default:
+ // copy
+ bits = new long[b.length];
+ System.arraycopy(b, 0, bits, 0, b.length);
+ }
+ }
+
+ @Override
+ boolean isEmpty() {
+ return bits.length == 1 && bits[0] == NO_PRIVILEGE;
+ }
+
+ @Override
+ long longValue() {
+ return (bits.length == 1) ? bits[0] : NO_PRIVILEGE;
+ }
+
+ @Override
+ long[] longValues() {
+ return bits;
+ }
+
+ @Override
+ boolean isSimple() {
+ return bits.length == 1;
+ }
+
+ @Override
+ Data next() {
+ throw new UnsupportedOperationException("Not implemented.");
+ }
+
+ @Override
+ boolean includes(Data other) {
+ if (bits.length == 1) {
+ return other.isSimple() && includes(bits[0], other.longValue());
+ } else {
+ return includes(bits, other.longValues());
+ }
+ }
+
+ @Override
+ boolean includes(long permissions) {
+ return (bits[0] & permissions) == permissions;
+ }
+
+ /**
+ * Add the other Data to this instance.
+ *
+ * @param other
+ */
+ private void add(Data other) {
+ if (other != this) {
+ if (bits.length == 1 && other.isSimple()) {
+ bits[0] |= other.longValue();
+ } else {
+ or(other.longValues());
+ }
+ }
+ }
+
+ /**
+ * Subtract the other Data from this instance.
+ *
+ * @param other
+ */
+ private void diff(Data other) {
+ if (bits.length == 1 && other.isSimple()) {
+ bits[0] = bits[0] & ~other.longValue();
+ } else {
+ bits = diff(bits, other.longValues());
+ }
+ }
+
+ /**
+ * Add the diff between the specified Data a and b.
+ *
+ * @param a
+ * @param b
+ */
+ private void addDifference(Data a, Data b) {
+ if (a.isSimple() && b.isSimple()) {
+ bits[0] |= a.longValue() & ~b.longValue();
+ } else {
+ long[] diff = diff(a.longValues(), b.longValues());
+ or(diff);
+ }
+ }
+
+ private void or(long[] b) {
+ if (b.length > bits.length) {
+ // enlarge the array
+ long[] res = new long[b.length];
+ System.arraycopy(bits, 0, res, 0, bits.length);
+ bits = res;
+ }
+ for (int i = 0; i < b.length; i++) {
+ bits[i] |= b[i];
+ }
+ }
+
+ private static long[] diff(long[] a, long[] b) {
+ int index = -1;
+ long[] res = new long[((a.length > b.length) ? a.length : b.length)];
+ for (int i = 0; i < res.length; i++) {
+ if (i < a.length && i < b.length) {
+ res[i] = a[i] & ~b[i];
+ } else {
+ res[i] = (i < a.length) ? a[i] : 0;
+ }
+ // remember start of trailing 0 array entries
+ if (res[i] != 0) {
+ index = -1;
+ } else if (index == -1) {
+ index = i;
+ }
+ }
+ switch (index) {
+ case -1:
+ // no need to remove trailing 0-long from the array
+ return res;
+ case 0:
+ // array consisting of one or multiple 0
+ return new long[]{NO_PRIVILEGE};
+ default:
+ // remove trailing 0-long entries from the array
+ long[] r2 = new long[index];
+ System.arraycopy(res, 0, r2, 0, index);
+ return r2;
+ }
+ }
+ }
+}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConstants.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConstants.java?rev=1445660&r1=1445659&r2=1445660&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConstants.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeConstants.java Wed Feb 13 15:19:34 2013
@@ -26,96 +26,165 @@ import org.apache.jackrabbit.JcrConstant
*/
public interface PrivilegeConstants {
- /** Internal (oak) name for the root node of the privilege store. */
+ /**
+ * Internal (oak) name for the root node of the privilege store.
+ */
String REP_PRIVILEGES = "rep:privileges";
- /** Internal (oak) path for the privilege store.*/
+ /**
+ * Internal (oak) path for the privilege store.
+ */
String PRIVILEGES_PATH = '/' + JcrConstants.JCR_SYSTEM + '/' + REP_PRIVILEGES;
- /** Node type name of the root node of the privilege store */
+ /**
+ * Node type name of the root node of the privilege store
+ */
String NT_REP_PRIVILEGES = "rep:Privileges";
- /** Node type name of the privilege definition nodes */
+ /**
+ * Node type name of the privilege definition nodes
+ */
String NT_REP_PRIVILEGE = "rep:Privilege";
- /** Name of the property that defines if the privilege is abstract. */
+ /**
+ * Name of the property that defines if the privilege is abstract.
+ */
String REP_IS_ABSTRACT = "rep:isAbstract";
- /** Name of the privilege definition property that stores the aggregate privilege names. */
+ /**
+ * Name of the privilege definition property that stores the aggregate privilege names.
+ */
String REP_AGGREGATES = "rep:aggregates";
+ /**
+ * TODO
+ */
+ String REP_NEXT = "rep:next";
+ /**
+ * TODO
+ */
+ String REP_BITS = "rep:bits";
- /** Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_READ} privilege */
+ /**
+ * Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_READ} privilege
+ */
String JCR_READ = "jcr:read";
- /** Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_MODIFY_PROPERTIES} privilege */
+ /**
+ * Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_MODIFY_PROPERTIES} privilege
+ */
String JCR_MODIFY_PROPERTIES = "jcr:modifyProperties";
- /** Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_ADD_CHILD_NODES} privilege */
+ /**
+ * Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_ADD_CHILD_NODES} privilege
+ */
String JCR_ADD_CHILD_NODES = "jcr:addChildNodes";
- /** Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_REMOVE_NODE} privilege */
+ /**
+ * Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_REMOVE_NODE} privilege
+ */
String JCR_REMOVE_NODE = "jcr:removeNode";
- /** Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_REMOVE_CHILD_NODES} privilege */
+ /**
+ * Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_REMOVE_CHILD_NODES} privilege
+ */
String JCR_REMOVE_CHILD_NODES = "jcr:removeChildNodes";
- /** Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_WRITE} privilege */
+ /**
+ * Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_WRITE} privilege
+ */
String JCR_WRITE = "jcr:write";
- /** Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_READ_ACCESS_CONTROL} privilege */
+ /**
+ * Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_READ_ACCESS_CONTROL} privilege
+ */
String JCR_READ_ACCESS_CONTROL = "jcr:readAccessControl";
- /** Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_MODIFY_ACCESS_CONTROL} privilege */
+ /**
+ * Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_MODIFY_ACCESS_CONTROL} privilege
+ */
String JCR_MODIFY_ACCESS_CONTROL = "jcr:modifyAccessControl";
- /** Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_LOCK_MANAGEMENT} privilege */
+ /**
+ * Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_LOCK_MANAGEMENT} privilege
+ */
String JCR_LOCK_MANAGEMENT = "jcr:lockManagement";
- /** Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_VERSION_MANAGEMENT} privilege */
+ /**
+ * Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_VERSION_MANAGEMENT} privilege
+ */
String JCR_VERSION_MANAGEMENT = "jcr:versionManagement";
- /** Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_NODE_TYPE_MANAGEMENT} privilege */
+ /**
+ * Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_NODE_TYPE_MANAGEMENT} privilege
+ */
String JCR_NODE_TYPE_MANAGEMENT = "jcr:nodeTypeManagement";
- /** Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_RETENTION_MANAGEMENT} privilege */
+ /**
+ * Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_RETENTION_MANAGEMENT} privilege
+ */
String JCR_RETENTION_MANAGEMENT = "jcr:retentionManagement";
- /** Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_LIFECYCLE_MANAGEMENT} privilege */
+ /**
+ * Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_LIFECYCLE_MANAGEMENT} privilege
+ */
String JCR_LIFECYCLE_MANAGEMENT = "jcr:lifecycleManagement";
- /** Internal (oak) name of the jcr:workspaceManagement privilege */
+ /**
+ * Internal (oak) name of the jcr:workspaceManagement privilege
+ */
String JCR_WORKSPACE_MANAGEMENT = "jcr:workspaceManagement";
- /** Internal (oak) name of the jcr:nodeTypeDefinitionManagement privilege */
+ /**
+ * Internal (oak) name of the jcr:nodeTypeDefinitionManagement privilege
+ */
String JCR_NODE_TYPE_DEFINITION_MANAGEMENT = "jcr:nodeTypeDefinitionManagement";
- /** Internal (oak) name of the jcr:namespaceManagement privilege */
+ /**
+ * Internal (oak) name of the jcr:namespaceManagement privilege
+ */
String JCR_NAMESPACE_MANAGEMENT = "jcr:namespaceManagement";
- /** Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_ALL} privilege */
+ /**
+ * Internal (oak) name of the {@link javax.jcr.security.Privilege#JCR_ALL} privilege
+ */
String JCR_ALL = "jcr:all";
- /** Internal (oak) name of the rep:privilegeManagement privilege */
+ /**
+ * Internal (oak) name of the rep:privilegeManagement privilege
+ */
String REP_PRIVILEGE_MANAGEMENT = "rep:privilegeManagement";
/**
* Internal (oak) name of the rep:userManagement privilege
+ *
* @since OAK 1.0
*/
String REP_USER_MANAGEMENT = "rep:userManagement";
- /** Internal (oak) name of the rep:write privilege */
+ /**
+ * Internal (oak) name of the rep:write privilege
+ */
String REP_WRITE = "rep:write";
- /** Internal (oak) name of the rep:readNodes privilege */
+ /**
+ * Internal (oak) name of the rep:readNodes privilege
+ */
String REP_READ_NODES = "rep:readNodes";
- /** Internal (oak) name of the rep:readProperties privilege */
+ /**
+ * Internal (oak) name of the rep:readProperties privilege
+ */
String REP_READ_PROPERTIES = "rep:readProperties";
- /** Internal (oak) name of the rep:addProperties privilege */
+ /**
+ * Internal (oak) name of the rep:addProperties privilege
+ */
String REP_ADD_PROPERTIES = "rep:addProperties";
- /** Internal (oak) name of the rep:alterProperties privilege */
+ /**
+ * Internal (oak) name of the rep:alterProperties privilege
+ */
String REP_ALTER_PROPERTIES = "rep:alterProperties";
- /** Internal (oak) name of the rep:removeProperties privilege */
+ /**
+ * Internal (oak) name of the rep:removeProperties privilege
+ */
String REP_REMOVE_PROPERTIES = "rep:removeProperties";
/**
@@ -123,4 +192,4 @@ public interface PrivilegeConstants {
* the {@link #NT_REP_PRIVILEGE rep:Privilege} node type
*/
Set<String> PRIVILEGE_PROPERTY_NAMES = ImmutableSet.of(REP_IS_ABSTRACT, REP_AGGREGATES);
-}
\ No newline at end of file
+}
Added: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionStore.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionStore.java?rev=1445660&view=auto
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionStore.java (added)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeDefinitionStore.java Wed Feb 13 15:19:34 2013
@@ -0,0 +1,318 @@
+/*
+ * 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.privilege;
+
+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.Set;
+import javax.annotation.CheckForNull;
+import javax.annotation.Nonnull;
+import javax.jcr.RepositoryException;
+
+import com.google.common.collect.ImmutableMap;
+import com.google.common.collect.ImmutableSet;
+import org.apache.jackrabbit.oak.api.CommitFailedException;
+import org.apache.jackrabbit.oak.api.Root;
+import org.apache.jackrabbit.oak.api.Tree;
+import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeDefinition;
+import org.apache.jackrabbit.oak.util.NodeUtil;
+import org.apache.jackrabbit.oak.util.TreeUtil;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Reads and writes privilege definitions from and to the repository content
+ * without applying any validation.
+ */
+public class PrivilegeDefinitionStore implements PrivilegeConstants {
+
+ private static final Logger log = LoggerFactory.getLogger(PrivilegeDefinitionStore.class);
+
+ /**
+ * The internal names of all built-in privileges that are not aggregates.
+ */
+ private static final String[] NON_AGGR_PRIVILEGES = new String[]{
+ REP_READ_NODES, REP_READ_PROPERTIES,
+ REP_ADD_PROPERTIES, REP_ALTER_PROPERTIES, REP_REMOVE_PROPERTIES,
+ JCR_ADD_CHILD_NODES, JCR_REMOVE_CHILD_NODES, JCR_REMOVE_NODE,
+ JCR_READ_ACCESS_CONTROL, JCR_MODIFY_ACCESS_CONTROL, JCR_NODE_TYPE_MANAGEMENT,
+ JCR_VERSION_MANAGEMENT, JCR_LOCK_MANAGEMENT, JCR_LIFECYCLE_MANAGEMENT,
+ JCR_RETENTION_MANAGEMENT, JCR_WORKSPACE_MANAGEMENT, JCR_NODE_TYPE_DEFINITION_MANAGEMENT,
+ JCR_NAMESPACE_MANAGEMENT, REP_PRIVILEGE_MANAGEMENT, REP_USER_MANAGEMENT};
+
+ /**
+ * The internal names and aggregation definition of all built-in privileges
+ * that are aggregates (except for jcr:all).
+ */
+ private static final Map<String, String[]> AGGREGATE_PRIVILEGES = ImmutableMap.of(
+ JCR_READ, new String[]{REP_READ_NODES, REP_READ_PROPERTIES},
+ JCR_MODIFY_PROPERTIES, new String[]{REP_ADD_PROPERTIES, REP_ALTER_PROPERTIES, REP_REMOVE_PROPERTIES},
+ JCR_WRITE, new String[]{JCR_MODIFY_PROPERTIES, JCR_ADD_CHILD_NODES, JCR_REMOVE_CHILD_NODES, JCR_REMOVE_NODE},
+ REP_WRITE, new String[]{JCR_WRITE, JCR_NODE_TYPE_MANAGEMENT});
+
+ private final Root root;
+ private final Map<PrivilegeBits, Set<String>> bitsToNames = new HashMap<PrivilegeBits, Set<String>>();
+
+ private PrivilegeBits next;
+
+ public PrivilegeDefinitionStore(Root root) {
+ this.root = root;
+ Tree privilegesTree = getPrivilegesTree();
+ if (privilegesTree != null && privilegesTree.hasProperty(REP_NEXT)) {
+ next = PrivilegeBits.getInstance(privilegesTree);
+ } else {
+ next = PrivilegeBits.BUILT_IN.get(REP_USER_MANAGEMENT).nextBits();
+ }
+ }
+
+ /**
+ * Returns the root tree for all privilege definitions stored in the content
+ * repository.
+ *
+ * @return The privileges root.
+ */
+ @CheckForNull
+ Tree getPrivilegesTree() {
+ return root.getTree(PRIVILEGES_PATH);
+ }
+
+ /**
+ * @param privilegeNames
+ * @return
+ */
+ @Nonnull
+ public PrivilegeBits getBits(@Nonnull String... privilegeNames) {
+ if (privilegeNames.length == 0) {
+ return PrivilegeBits.EMPTY;
+ }
+
+ Tree privilegesTree = getPrivilegesTree();
+ if (privilegesTree == null) {
+ return PrivilegeBits.EMPTY;
+ }
+ PrivilegeBits bits = PrivilegeBits.getInstance();
+ for (String privilegeName : privilegeNames) {
+ Tree defTree = privilegesTree.getChild(privilegeName);
+ if (defTree != null) {
+ bits.add(PrivilegeBits.getInstance(defTree));
+ }
+ }
+ return bits.unmodifiable();
+ }
+
+ /**
+ * Resolve the given privilege bits to a set of privilege names.
+ *
+ * @param privilegeBits An instance of privilege bits.
+ * @return The names of the registed privileges associated with the given
+ * bits. Any bits that don't have a corresponding privilege definition will
+ * be ignored.
+ */
+ @Nonnull
+ public Set<String> getPrivilegeNames(PrivilegeBits privilegeBits) {
+ if (privilegeBits == null || privilegeBits.isEmpty()) {
+ return Collections.emptySet();
+ } else if (bitsToNames.containsKey(privilegeBits)) {
+ // matches all built-in aggregates and single built-in privileges
+ return bitsToNames.get(privilegeBits);
+ } else {
+ Tree privilegesTree = getPrivilegesTree();
+ if (privilegesTree == null) {
+ return Collections.emptySet();
+ }
+
+ if (bitsToNames.isEmpty()) {
+ for (Tree child : privilegesTree.getChildren()) {
+ bitsToNames.put(PrivilegeBits.getInstance(child), Collections.singleton(child.getName()));
+ }
+ }
+
+ Set<String> privilegeNames;
+ if (bitsToNames.containsKey(privilegeBits)) {
+ privilegeNames = bitsToNames.get(privilegeBits);
+ } else {
+ privilegeNames = new HashSet<String>();
+ Set<String> aggregates = new HashSet<String>();
+ for (Tree child : privilegesTree.getChildren()) {
+ PrivilegeBits bits = PrivilegeBits.getInstance(child);
+ if (privilegeBits.includes(bits)) {
+ privilegeNames.add(child.getName());
+ if (child.hasProperty(REP_AGGREGATES)) {
+ aggregates.addAll(readDefinition(child).getDeclaredAggregateNames());
+ }
+ }
+ }
+ privilegeNames.removeAll(aggregates);
+ bitsToNames.put(privilegeBits.unmodifiable(), ImmutableSet.copyOf(privilegeNames));
+ }
+ return privilegeNames;
+ }
+ }
+
+ /**
+ * Read all registered privilege definitions from the content.
+ *
+ * @return All privilege definitions stored in the content.
+ */
+ @Nonnull
+ public Map<String, PrivilegeDefinition> readDefinitions() {
+ Tree privilegesTree = getPrivilegesTree();
+ if (privilegesTree == null) {
+ return Collections.emptyMap();
+ } else {
+ Map<String, PrivilegeDefinition> definitions = new HashMap<String, PrivilegeDefinition>();
+ for (Tree child : privilegesTree.getChildren()) {
+ PrivilegeDefinition def = readDefinition(child);
+ definitions.put(def.getName(), def);
+ }
+ return definitions;
+ }
+ }
+
+ /**
+ * Retrieve the privilege definition with the specified {@code privilegeName}.
+ *
+ * @param privilegeName The name of a registered privilege definition.
+ * @return The privilege definition with the specified name or {@code null}
+ * if the name doesn't refer to a registered privilege.
+ */
+ @CheckForNull
+ public PrivilegeDefinition readDefinition(String privilegeName) {
+ Tree privilegesTree = getPrivilegesTree();
+ if (privilegesTree == null) {
+ return null;
+ } else {
+ Tree definitionTree = privilegesTree.getChild(privilegeName);
+ return (definitionTree == null) ? null : readDefinition(definitionTree);
+ }
+ }
+
+ /**
+ * @param definitionTree
+ * @return
+ */
+ @Nonnull
+ static PrivilegeDefinition readDefinition(@Nonnull Tree definitionTree) {
+ String name = definitionTree.getName();
+ boolean isAbstract = TreeUtil.getBoolean(definitionTree, REP_IS_ABSTRACT);
+ String[] declAggrNames = TreeUtil.getStrings(definitionTree, REP_AGGREGATES);
+
+ return new PrivilegeDefinitionImpl(name, isAbstract, declAggrNames);
+ }
+
+ /**
+ * Write the given privilege definition to the repository content.
+ *
+ * @param definition The new privilege definition.
+ * @throws RepositoryException If the definition can't be written.
+ */
+ public void writeDefinition(PrivilegeDefinition definition) throws RepositoryException {
+ writeDefinitions(Collections.singleton(definition));
+ }
+
+ /**
+ * Create the built-in privilege definitions during repository setup.
+ *
+ * @throws RepositoryException If an error occurs.
+ */
+ void writeBuiltInDefinitions() throws RepositoryException {
+ writeDefinitions(getBuiltInDefinitions());
+ }
+
+ //------------------------------------------------------------< private >---
+
+ /**
+ * @param definitions
+ * @throws RepositoryException
+ */
+ private void writeDefinitions(Iterable<PrivilegeDefinition> definitions) throws RepositoryException {
+ try {
+ // make sure the privileges path is defined
+ Tree privilegesTree = getPrivilegesTree();
+ if (privilegesTree == null) {
+ throw new RepositoryException("Privilege store does not exist.");
+ }
+ NodeUtil privilegesNode = new NodeUtil(getPrivilegesTree());
+ for (PrivilegeDefinition definition : definitions) {
+ if (privilegesNode.hasChild(definition.getName())) {
+ throw new RepositoryException("Privilege definition with name '" + definition.getName() + "' already exists.");
+ }
+ writePrivilegeNode(privilegesNode, definition);
+ }
+ /*
+ update the property storing the next privilege bits with the
+ privileges root tree. this is a cheap way to detect collisions that
+ may arise from concurrent registration of custom privileges.
+ */
+ next.writeTo(privilegesTree);
+
+ // delegate validation to the commit validation (see above)
+ root.commit();
+
+ } catch (CommitFailedException e) {
+ Throwable t = e.getCause();
+ if (t instanceof RepositoryException) {
+ throw (RepositoryException) t;
+ } else {
+ throw new RepositoryException(e);
+ }
+ }
+ }
+
+ private void writePrivilegeNode(NodeUtil privilegesNode, PrivilegeDefinition definition) {
+ String name = definition.getName();
+ NodeUtil privNode = privilegesNode.addChild(name, NT_REP_PRIVILEGE);
+ if (definition.isAbstract()) {
+ privNode.setBoolean(REP_IS_ABSTRACT, true);
+ }
+ String[] declAggrNames = definition.getDeclaredAggregateNames().toArray(new String[definition.getDeclaredAggregateNames().size()]);
+ boolean isAggregate = declAggrNames.length > 0;
+ if (isAggregate) {
+ privNode.setNames(REP_AGGREGATES, declAggrNames);
+ }
+
+ PrivilegeBits bits;
+ if (PrivilegeBits.BUILT_IN.containsKey(name)) {
+ bits = PrivilegeBits.BUILT_IN.get(name);
+ } else if (isAggregate) {
+ bits = getBits(declAggrNames);
+ } else {
+ bits = next;
+ next = bits.nextBits();
+ }
+ bits.writeTo(privNode.getTree());
+ }
+
+ private static Collection<PrivilegeDefinition> getBuiltInDefinitions() {
+ Map<String, PrivilegeDefinition> definitions = new LinkedHashMap<String, PrivilegeDefinition>();
+ for (String privilegeName : NON_AGGR_PRIVILEGES) {
+ PrivilegeDefinition def = new PrivilegeDefinitionImpl(privilegeName, false);
+ definitions.put(privilegeName, def);
+ }
+ for (String privilegeName : AGGREGATE_PRIVILEGES.keySet()) {
+ PrivilegeDefinition def = new PrivilegeDefinitionImpl(privilegeName, false, AGGREGATE_PRIVILEGES.get(privilegeName));
+ definitions.put(privilegeName, def);
+ }
+ PrivilegeDefinition all = new PrivilegeDefinitionImpl(JCR_ALL, false, definitions.keySet());
+ definitions.put(JCR_ALL, all);
+ return definitions.values();
+ }
+}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeInitializer.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeInitializer.java?rev=1445660&r1=1445659&r2=1445660&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeInitializer.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeInitializer.java Wed Feb 13 15:19:34 2013
@@ -16,13 +16,9 @@
*/
package org.apache.jackrabbit.oak.security.privilege;
-import java.util.Collection;
-import java.util.LinkedHashMap;
-import java.util.Map;
import javax.jcr.RepositoryException;
-import com.google.common.collect.ImmutableMap;
import org.apache.jackrabbit.JcrConstants;
import org.apache.jackrabbit.oak.api.CommitFailedException;
import org.apache.jackrabbit.oak.api.Type;
@@ -30,7 +26,6 @@ import org.apache.jackrabbit.oak.core.Ro
import org.apache.jackrabbit.oak.plugins.memory.MemoryNodeStore;
import org.apache.jackrabbit.oak.plugins.nodetype.NodeTypeConstants;
import org.apache.jackrabbit.oak.spi.lifecycle.RepositoryInitializer;
-import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeDefinition;
import org.apache.jackrabbit.oak.spi.state.NodeBuilder;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.oak.spi.state.NodeStore;
@@ -48,24 +43,6 @@ class PrivilegeInitializer implements Re
private static final Logger log = LoggerFactory.getLogger(PrivilegeInitializer.class);
- /** The internal names of all built-in privileges that are not aggregates. */
- private static final String[] NON_AGGR_PRIVILEGES = new String[] {
- REP_READ_NODES, REP_READ_PROPERTIES,
- REP_ADD_PROPERTIES, REP_ALTER_PROPERTIES, REP_REMOVE_PROPERTIES,
- JCR_ADD_CHILD_NODES, JCR_REMOVE_CHILD_NODES, JCR_REMOVE_NODE,
- JCR_READ_ACCESS_CONTROL, JCR_MODIFY_ACCESS_CONTROL, JCR_NODE_TYPE_MANAGEMENT,
- JCR_VERSION_MANAGEMENT, JCR_LOCK_MANAGEMENT, JCR_LIFECYCLE_MANAGEMENT,
- JCR_RETENTION_MANAGEMENT, JCR_WORKSPACE_MANAGEMENT, JCR_NODE_TYPE_DEFINITION_MANAGEMENT,
- JCR_NAMESPACE_MANAGEMENT, REP_PRIVILEGE_MANAGEMENT, REP_USER_MANAGEMENT};
-
- /** The internal names and aggregation definition of all built-in privileges
- that are aggregates (except for jcr:all). */
- private static final Map<String, String[]> AGGREGATE_PRIVILEGES = ImmutableMap.of(
- JCR_READ, new String[] {REP_READ_NODES, REP_READ_PROPERTIES},
- JCR_MODIFY_PROPERTIES, new String[] {REP_ADD_PROPERTIES, REP_ALTER_PROPERTIES, REP_REMOVE_PROPERTIES},
- JCR_WRITE, new String[] {JCR_MODIFY_PROPERTIES, JCR_ADD_CHILD_NODES, JCR_REMOVE_CHILD_NODES, JCR_REMOVE_NODE},
- REP_WRITE, new String[] {JCR_WRITE, JCR_NODE_TYPE_MANAGEMENT});
-
@Override
public NodeState initialize(NodeState state) {
NodeBuilder root = state.builder();
@@ -86,9 +63,8 @@ class PrivilegeInitializer implements Re
throw new RuntimeException(e);
}
- PrivilegeDefinitionWriter writer = new PrivilegeDefinitionWriter(new RootImpl(store));
try {
- writer.writeDefinitions(getBuiltInDefinitions());
+ new PrivilegeDefinitionStore(new RootImpl(store)).writeBuiltInDefinitions();
} catch (RepositoryException e) {
log.error("Failed to register built-in privileges", e);
throw new RuntimeException(e);
@@ -97,19 +73,4 @@ class PrivilegeInitializer implements Re
}
return root.getNodeState();
}
-
- private Collection<PrivilegeDefinition> getBuiltInDefinitions() {
- Map<String, PrivilegeDefinition> definitions = new LinkedHashMap<String, PrivilegeDefinition>();
- for (String privilegeName : NON_AGGR_PRIVILEGES) {
- PrivilegeDefinition def = new PrivilegeDefinitionImpl(privilegeName, false);
- definitions.put(privilegeName, def);
- }
- for (String privilegeName : AGGREGATE_PRIVILEGES.keySet()) {
- PrivilegeDefinition def = new PrivilegeDefinitionImpl(privilegeName, false, AGGREGATE_PRIVILEGES.get(privilegeName));
- definitions.put(privilegeName, def);
- }
- PrivilegeDefinition all = new PrivilegeDefinitionImpl(JCR_ALL, false, definitions.keySet());
- definitions.put(JCR_ALL, all);
- return definitions.values();
- }
}
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeManagerImpl.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeManagerImpl.java?rev=1445660&r1=1445659&r2=1445660&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeManagerImpl.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeManagerImpl.java Wed Feb 13 15:19:34 2013
@@ -81,9 +81,9 @@ public class PrivilegeManagerImpl implem
if (privilegeName == null || privilegeName.isEmpty()) {
throw new RepositoryException("Invalid privilege name " + privilegeName);
}
- PrivilegeDefinition definition = new PrivilegeDefinitionImpl(getOakName(privilegeName), isAbstract, getOakNames(declaredAggregateNames));
- PrivilegeDefinitionWriter writer = new PrivilegeDefinitionWriter(getWriteRoot());
- writer.writeDefinition(definition);
+ PrivilegeDefinitionImpl definition = new PrivilegeDefinitionImpl(getOakName(privilegeName), isAbstract, getOakNames(declaredAggregateNames));
+ PrivilegeDefinitionStore store = getStore(getWriteRoot());
+ store.writeDefinition(definition);
// refresh the current root to make sure the definition is visible
root.refresh();
@@ -130,18 +130,18 @@ public class PrivilegeManagerImpl implem
@Nonnull
private PrivilegeDefinition[] getPrivilegeDefinitions() {
- Map<String, PrivilegeDefinition> definitions = getReader().readDefinitions();
+ Map<String, PrivilegeDefinition> definitions = getStore(root).readDefinitions();
return definitions.values().toArray(new PrivilegeDefinition[definitions.size()]);
}
@CheckForNull
private PrivilegeDefinition getPrivilegeDefinition(String oakName) {
- return getReader().readDefinition(oakName);
+ return getStore(root).readDefinition(oakName);
}
@Nonnull
- private PrivilegeDefinitionReader getReader() {
- return new PrivilegeDefinitionReader(root);
+ private static PrivilegeDefinitionStore getStore(Root targetRoot) {
+ return new PrivilegeDefinitionStore(targetRoot);
}
//--------------------------------------------------------------------------
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeMigrator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeMigrator.java?rev=1445660&r1=1445659&r2=1445660&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeMigrator.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeMigrator.java Wed Feb 13 15:19:34 2013
@@ -48,7 +48,7 @@ import org.xml.sax.helpers.DefaultHandle
/**
* PrivilegeMigrator is a utility to migrate custom privilege definitions from
* a jackrabbit 2 project to oak.
- *
+ * <p/>
* TODO: this is an initial draft of a migration tool from jr2 custom privileges
* TODO: to oak. might need to be adjusted once we have defined a upgrade path (see OAK-458)
*/
@@ -62,7 +62,7 @@ public class PrivilegeMigrator {
public void migrateCustomPrivileges(InputStream privilegeStream) throws RepositoryException {
final Root root = contentSession.getLatestRoot();
- PrivilegeDefinitionWriter writer = new PrivilegeDefinitionWriter(root);
+ PrivilegeDefinitionStore store = new PrivilegeDefinitionStore(root);
try {
NamespaceRegistry nsRegistry = new ReadWriteNamespaceRegistry() {
@Override
@@ -75,8 +75,9 @@ public class PrivilegeMigrator {
return root.getTree("/");
}
};
- Iterable<PrivilegeDefinition> custom = readCustomDefinitons(privilegeStream, nsRegistry);
- writer.writeDefinitions(custom);
+ for (PrivilegeDefinition def : readCustomDefinitons(privilegeStream, nsRegistry)) {
+ store.writeDefinition(def);
+ }
} catch (IOException e) {
throw new RepositoryException(e);
}
@@ -95,7 +96,7 @@ public class PrivilegeMigrator {
* @throws IOException
*/
private static Iterable<PrivilegeDefinition> readCustomDefinitons(InputStream customPrivileges,
- NamespaceRegistry nsRegistry) throws RepositoryException, IOException {
+ NamespaceRegistry nsRegistry) throws RepositoryException, IOException {
Map<String, PrivilegeDefinition> definitions = new LinkedHashMap<String, PrivilegeDefinition>();
InputSource src = new InputSource(customPrivileges);
for (PrivilegeDefinition def : PrivilegeXmlHandler.readDefinitions(src, nsRegistry)) {
@@ -109,6 +110,7 @@ public class PrivilegeMigrator {
}
//--------------------------------------------------------------------------
+
/**
* The {@code PrivilegeXmlHandler} loads privilege definitions from a XML
* document using the following format:
@@ -175,7 +177,8 @@ public class PrivilegeMigrator {
/**
* Build a new {@code PrivilegeDefinition} from the given XML node.
- * @param n the xml node storing the privilege definition.
+ *
+ * @param n the xml node storing the privilege definition.
* @param nsRegistry
* @return a new PrivilegeDefinition.
* @throws javax.jcr.RepositoryException
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidator.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidator.java?rev=1445660&r1=1445659&r2=1445660&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidator.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidator.java Wed Feb 13 15:19:34 2013
@@ -33,6 +33,8 @@ import org.apache.jackrabbit.oak.spi.com
import org.apache.jackrabbit.oak.spi.security.privilege.PrivilegeDefinition;
import org.apache.jackrabbit.oak.spi.state.NodeState;
import org.apache.jackrabbit.util.Text;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
/**
* Validator implementation that is responsible for validating any modifications
@@ -40,11 +42,14 @@ import org.apache.jackrabbit.util.Text;
*/
class PrivilegeValidator implements PrivilegeConstants, Validator {
- private final Map<String, PrivilegeDefinition> definitions;
+ private static final Logger log = LoggerFactory.getLogger(PrivilegeValidator.class);
- PrivilegeValidator(NodeState before) {
- PrivilegeDefinitionReader reader = new PrivilegeDefinitionReader(new ReadOnlyRoot(before));
- definitions = reader.readDefinitions();
+ private final PrivilegeDefinitionStore storeBefore;
+ private final PrivilegeDefinitionStore storeAfter;
+
+ PrivilegeValidator(NodeState before, NodeState after) {
+ storeBefore = new PrivilegeDefinitionStore(new ReadOnlyRoot(before));
+ storeAfter = new PrivilegeDefinitionStore((new ReadOnlyRoot(after)));
}
//----------------------------------------------------------< Validator >---
@@ -55,7 +60,11 @@ class PrivilegeValidator implements Priv
@Override
public void propertyChanged(PropertyState before, PropertyState after) throws CommitFailedException {
- throw new CommitFailedException("Attempt to modify existing privilege definition.");
+ if (REP_NEXT.equals(before.getName())) {
+ validateNext(PrivilegeBits.getInstance(storeBefore.getPrivilegesTree().getProperty(REP_NEXT)));
+ } else {
+ throw new CommitFailedException("Attempt to modify existing privilege definition.");
+ }
}
@Override
@@ -65,6 +74,7 @@ class PrivilegeValidator implements Priv
@Override
public Validator childNodeAdded(String name, NodeState after) throws CommitFailedException {
+ checkInitialized();
// the following characteristics are expected to be validated elsewhere:
// - permission to allow privilege registration -> permission validator.
// - name collisions (-> delegated to NodeTypeValidator since sms are not allowed)
@@ -84,8 +94,7 @@ class PrivilegeValidator implements Priv
}
// additional validation of the definition
- PrivilegeDefinition def = PrivilegeDefinitionReader.readDefinition(tree);
- validateDefinition(def);
+ validateDefinition(tree);
// privilege definitions may not have child nodes.
return null;
@@ -102,29 +111,65 @@ class PrivilegeValidator implements Priv
}
//------------------------------------------------------------< private >---
+ private void checkInitialized() throws CommitFailedException {
+ if (storeBefore.getPrivilegesTree() == null) {
+ throw new CommitFailedException("Privilege store not initialized.");
+ }
+ }
+
+ private void validateNext(PrivilegeBits bits) throws CommitFailedException {
+ PrivilegeBits next = PrivilegeBits.getInstance(storeAfter.getPrivilegesTree().getProperty(REP_NEXT));
+ if (!next.equals(bits.nextBits())) {
+ throw new CommitFailedException("Next bits not updated.");
+ }
+ }
+
+ private void validateBits(PrivilegeBits bits, PrivilegeBits expectedNext) throws CommitFailedException {
+ if (!expectedNext.equals(bits.nextBits())) {
+ throw new CommitFailedException("PrivilegeBits violation: Expected " + expectedNext + "; Found" + bits + '.');
+ }
+ }
/**
* Validation of the privilege definition including the following steps:
* <p/>
+ * - privilege bits must not collide with an existing privilege
+ * - next bits must have been adjusted in case of a non-aggregate privilege
* - all aggregates must have been registered before
* - no existing privilege defines the same aggregation
* - no cyclic aggregation
*
- * @param definition The new privilege definition to validate.
+ * @param definitionTree The new privilege definition tree to validate.
* @throws org.apache.jackrabbit.oak.api.CommitFailedException
* If any of
* the checks listed above fails.
*/
- private void validateDefinition(PrivilegeDefinition definition) throws CommitFailedException {
+ private void validateDefinition(Tree definitionTree) throws CommitFailedException {
+ PrivilegeBits newBits = PrivilegeBits.getInstance(definitionTree);
+ if (newBits.isEmpty()) {
+ throw new CommitFailedException("PrivilegeBits are missing.");
+ }
+
+ Set<String> privNames = storeBefore.getPrivilegeNames(newBits);
+ PrivilegeDefinition definition = PrivilegeDefinitionStore.readDefinition(definitionTree);
Set<String> declaredNames = definition.getDeclaredAggregateNames();
+
+ // non-aggregate privilege
if (declaredNames.isEmpty()) {
+ if (!privNames.isEmpty()) {
+ throw new CommitFailedException("PrivilegeBits already in used.");
+ }
+ validateNext(newBits);
return;
}
+ // aggregation of a single privilege
if (declaredNames.size() == 1) {
throw new CommitFailedException("Singular aggregation is equivalent to existing privilege.");
}
+ // aggregation of >1 privileges
+ Map<String, PrivilegeDefinition> definitions = storeBefore.readDefinitions();
for (String aggrName : declaredNames) {
// aggregated privilege not registered
if (!definitions.containsKey(aggrName)) {
@@ -132,13 +177,13 @@ class PrivilegeValidator implements Priv
}
// check for circular aggregation
- if (isCircularAggregation(definition.getName(), aggrName)) {
+ if (isCircularAggregation(definition.getName(), aggrName, definitions)) {
String msg = "Detected circular aggregation within custom privilege caused by " + aggrName;
throw new CommitFailedException(msg);
}
}
- Set<String> aggregateNames = resolveAggregates(declaredNames);
+ Set<String> aggregateNames = resolveAggregates(declaredNames, definitions);
for (PrivilegeDefinition existing : definitions.values()) {
Set<String> existingDeclared = existing.getDeclaredAggregateNames();
if (existingDeclared.isEmpty()) {
@@ -146,14 +191,20 @@ class PrivilegeValidator implements Priv
}
// test for exact same aggregation or aggregation with the same net effect
- if (declaredNames.equals(existingDeclared) || aggregateNames.equals(resolveAggregates(existingDeclared))) {
+ if (declaredNames.equals(existingDeclared) || aggregateNames.equals(resolveAggregates(existingDeclared, definitions))) {
String msg = "Custom aggregate privilege '" + definition.getName() + "' is already covered by '" + existing.getName() + '\'';
throw new CommitFailedException(msg);
}
}
+
+ PrivilegeBits aggrBits = storeBefore.getBits(declaredNames.toArray(new String[declaredNames.size()]));
+ if (!newBits.equals(aggrBits)) {
+ throw new CommitFailedException("Invalid privilege bits for aggregated privilege definition.");
+ }
}
- private boolean isCircularAggregation(String privilegeName, String aggregateName) {
+ private static boolean isCircularAggregation(String privilegeName, String aggregateName,
+ Map<String, PrivilegeDefinition> definitions) {
if (privilegeName.equals(aggregateName)) {
return true;
}
@@ -168,14 +219,14 @@ class PrivilegeValidator implements Priv
return true;
}
if (definitions.containsKey(name)) {
- isCircular = isCircularAggregation(privilegeName, name);
+ isCircular = isCircularAggregation(privilegeName, name, definitions);
}
}
return isCircular;
}
}
- private Set<String> resolveAggregates(Set<String> declared) throws CommitFailedException {
+ private static Set<String> resolveAggregates(Set<String> declared, Map<String, PrivilegeDefinition> definitions) throws CommitFailedException {
Set<String> aggregateNames = new HashSet<String>();
for (String name : declared) {
PrivilegeDefinition d = definitions.get(name);
@@ -187,7 +238,7 @@ class PrivilegeValidator implements Priv
if (names.isEmpty()) {
aggregateNames.add(name);
} else {
- aggregateNames.addAll(resolveAggregates(names));
+ aggregateNames.addAll(resolveAggregates(names, definitions));
}
}
return aggregateNames;
Modified: jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidatorProvider.java
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidatorProvider.java?rev=1445660&r1=1445659&r2=1445660&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidatorProvider.java (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/java/org/apache/jackrabbit/oak/security/privilege/PrivilegeValidatorProvider.java Wed Feb 13 15:19:34 2013
@@ -36,6 +36,6 @@ class PrivilegeValidatorProvider impleme
@Nonnull
@Override
public Validator getRootValidator(NodeState before, NodeState after) {
- return new SubtreeValidator(new PrivilegeValidator(before), JCR_SYSTEM, REP_PRIVILEGES);
+ return new SubtreeValidator(new PrivilegeValidator(before, after), JCR_SYSTEM, REP_PRIVILEGES);
}
}
\ No newline at end of file
Modified: jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd
URL: http://svn.apache.org/viewvc/jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd?rev=1445660&r1=1445659&r2=1445660&view=diff
==============================================================================
--- jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd (original)
+++ jackrabbit/oak/trunk/oak-core/src/main/resources/org/apache/jackrabbit/oak/plugins/nodetype/write/builtin_nodetypes.cnd Wed Feb 13 15:19:34 2013
@@ -615,7 +615,7 @@
*/
[rep:Permissions]
- rep:accessControlledPath (PATH) protected mandatory
- - rep:privilegeBits (UNDEFINED) protected mandatory
+ - rep:privileges (UNDEFINED) protected mandatory
- rep:index (LONG) protected mandatory
- * (UNDEFINED) protected
@@ -661,7 +661,7 @@
[rep:Members]
orderable
+ * (rep:Members) = rep:Members protected multiple /* FIXME: SNS definition */
- - * (WEAKREFERENCE) protected < 'rep:Authorizable' /* Deprecated since OAK */
+ - * (WEAKREFERENCE) protected < 'rep:Authorizable' /* Deprecated since oak 1.0 */
- rep:members (WEAKREFERENCE) protected multiple < 'rep:Authorizable' /* @since oak 1.0 */
// -----------------------------------------------------------------------------
@@ -673,6 +673,7 @@
*/
[rep:Privileges]
+ * (rep:Privilege) = rep:Privilege protected ABORT
+ - rep:next (LONG) protected multiple mandatory
/**
* @since oak 1.0
@@ -680,6 +681,7 @@
[rep:Privilege]
- rep:isAbstract (BOOLEAN) protected
- rep:aggregates (NAME) protected multiple
+ - rep:bits (LONG) protected multiple mandatory
// -----------------------------------------------------------------------------
// Token Management