You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@rya.apache.org by ca...@apache.org on 2017/06/01 01:22:22 UTC

[2/3] incubator-rya git commit: RYA-119 Added MongoDB Column Visibility (called Document Visibility). This adds a new field to each document called documentVisibility which uses a boolean expression to determine if the user can access the document. The b

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/cc1cc712/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/util/DisjunctiveNormalFormConverter.java
----------------------------------------------------------------------
diff --git a/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/util/DisjunctiveNormalFormConverter.java b/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/util/DisjunctiveNormalFormConverter.java
new file mode 100644
index 0000000..43d3e13
--- /dev/null
+++ b/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/util/DisjunctiveNormalFormConverter.java
@@ -0,0 +1,270 @@
+/*
+ * 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.rya.mongodb.document.util;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Set;
+
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.core.security.ColumnVisibility.Node;
+import org.apache.accumulo.core.security.ColumnVisibility.NodeType;
+import org.apache.commons.lang.StringUtils;
+import org.apache.log4j.Logger;
+import org.apache.rya.mongodb.document.visibility.DocumentVisibility;
+
+import com.google.common.base.Joiner;
+import com.google.common.collect.Lists;
+
+/**
+ * Utility for converting document visibility boolean expressions into
+ * Disjunctive Normal Form.
+ */
+public final class DisjunctiveNormalFormConverter {
+    private static final Logger log = Logger.getLogger(DisjunctiveNormalFormConverter.class);
+
+    /**
+     * Private constructor to prevent instantiation.
+     */
+    private DisjunctiveNormalFormConverter() {
+    }
+
+    /**
+     * Creates a new document visibility based on the boolean expression string
+     * that is converted into disjunctive normal form.
+     * @param expression the boolean string expression.
+     * @return the {@link DocumentVisibility} in DNF.
+     */
+    public static DocumentVisibility createDnfDocumentVisibility(final String expression) {
+        return createDnfDocumentVisibility(expression.getBytes(UTF_8));
+    }
+
+    /**
+     * Creates a new document visibility based on the boolean expression that is
+     * converted into disjunctive normal form.
+     * @param expression the boolean expression bytes.
+     * @return the {@link DocumentVisibility} in DNF.
+     */
+    public static DocumentVisibility createDnfDocumentVisibility(final byte[] expression) {
+        final DocumentVisibility documentVisibility = new DocumentVisibility(expression);
+        final DocumentVisibility dnfDv = convertToDisjunctiveNormalForm(documentVisibility);
+        return dnfDv;
+    }
+
+    /**
+     * Creates a document visibility boolean expression string into Disjunctive
+     * Normal Form (DNF).  Expressions use this format in DNF:<pre>
+     * (P1 & P2 & P3 ... Pn) | (Q1 & Q2 ... Qm) ...
+     * </pre>
+     * @param documentVisibility the {@link DocumentVisibility}.
+     * @return a new {@link DocumentVisibility} with its expression in DNF.
+     */
+    public static DocumentVisibility convertToDisjunctiveNormalForm(final DocumentVisibility documentVisibility) {
+        // Find all the terms used in the expression
+        final List<String> terms = findNodeTerms(documentVisibility.getParseTree(), documentVisibility.getExpression());
+        // Create an appropriately sized truth table that has the correct 0's
+        // and 1's in place based on the number of terms.
+        // This size should be [numberOfTerms][2 ^ numberOfTerms].
+        final byte[][] truthTable = createTruthTableInputs(terms);
+
+        // Go through each row in the truth table.
+        // If the row has a 1 for the term then create an Authorization for it
+        // and test if it works.
+        // If the row passes then that means all the terms that were a 1 and
+        // were used can be AND'ed together to pass the expression.
+        // All the rows that pass can be OR'd together.
+        // Disjunction Normal Form: (P1 & P2 & P3 ... Pn) | (Q1 & Q2 ... Qm) ...
+        final List<List<String>> termRowsThatPass = new ArrayList<>();
+        for (final byte[] row : truthTable) {
+            final List<String> termRowToCheck = new ArrayList<>();
+            // If the truth table input is a 1 then include the corresponding
+            // term that it matches.
+            for (int i = 0; i < row.length; i++) {
+                final byte entry = row[i];
+                if (entry == 1) {
+                    termRowToCheck.add(terms.get(i));
+                }
+            }
+
+            final List<String> authList = new ArrayList<>();
+            for (final String auth : termRowToCheck) {
+                String formattedAuth = auth;
+                formattedAuth = StringUtils.removeStart(formattedAuth, "\"");
+                formattedAuth = StringUtils.removeEnd(formattedAuth, "\"");
+                authList.add(formattedAuth);
+            }
+            final Authorizations auths = new Authorizations(authList.toArray(new String[0]));
+            final boolean hasAccess = DocumentVisibilityUtil.doesUserHaveDocumentAccess(auths, documentVisibility, false);
+            if (hasAccess) {
+                boolean alreadyCoveredBySimplerTerms = false;
+                // If one 'AND' group is (A&C) and another is (A&B&C) then we
+                // can drop (A&B&C) since it is already covered by simpler terms
+                // (it's a subset)
+                for (final List<String> existingTermRowThatPassed : termRowsThatPass) {
+                    alreadyCoveredBySimplerTerms = termRowToCheck.containsAll(existingTermRowThatPassed);
+                    if (alreadyCoveredBySimplerTerms) {
+                        break;
+                    }
+                }
+                if (!alreadyCoveredBySimplerTerms) {
+                    termRowsThatPass.add(termRowToCheck);
+                }
+            }
+        }
+
+        // Rebuild the term rows that passed as a document visibility boolean
+        // expression string.
+        final StringBuilder sb = new StringBuilder();
+        boolean isFirst = true;
+        final boolean hasMultipleGroups = termRowsThatPass.size() > 1;
+        for (final List<String> termRowThatPassed : termRowsThatPass) {
+            if (isFirst) {
+                isFirst = false;
+            } else {
+                sb.append("|");
+            }
+            if (hasMultipleGroups && termRowThatPassed.size() > 1) {
+                sb.append("(");
+            }
+            sb.append(Joiner.on("&").join(termRowThatPassed));
+            if (hasMultipleGroups && termRowThatPassed.size() > 1) {
+                sb.append(")");
+            }
+        }
+
+        log.trace(sb.toString());
+        final DocumentVisibility dnfDv = new DocumentVisibility(sb.toString());
+        return dnfDv;
+    }
+
+    /**
+     * Searches a node for all unique terms in its expression and returns them.
+     * Duplicates are not included.
+     * @param node the {@link Node}.
+     * @return an unmodifiable {@link List} of string terms without duplicates.
+     */
+    public static List<String> findNodeTerms(final Node node, final byte[] expression) {
+        final Set<String> terms = new LinkedHashSet<>();
+        if (node.getType() == NodeType.TERM) {
+            final String data = DocumentVisibilityUtil.getTermNodeData(node, expression);
+            terms.add(data);
+        }
+        for (final Node child : node.getChildren()) {
+            switch (node.getType()) {
+                case AND:
+                case OR:
+                    terms.addAll(findNodeTerms(child, expression));
+                    break;
+                default:
+                    break;
+            }
+        }
+        return Collections.unmodifiableList(Lists.newArrayList(terms));
+    }
+
+    /**
+     * Creates the inputs needed to populate a truth table based on the provided
+     * number of terms that the expression uses. So, a node that only has 3
+     * terms will create a 3 x 8 size table:
+     * <pre>
+     * 0 0 0
+     * 0 0 1
+     * 0 1 0
+     * 0 1 1
+     * 1 0 0
+     * 1 0 1
+     * 1 1 0
+     * 1 1 1
+     * </pre>
+     * @param node the {@link Node}.
+     * @return a two-dimensional array of bytes representing the truth table
+     * inputs.  The table will be of size: [termNumber] x [2 ^ termNumber]
+     */
+    public static byte[][] createTruthTableInputs(final Node node, final byte[] expression) {
+        final List<String> terms = findNodeTerms(node, expression);
+        return createTruthTableInputs(terms);
+    }
+
+    /**
+     * Creates the inputs needed to populate a truth table based on the provided
+     * number of terms that the expression uses. So, if there are 3 terms then
+     * it will create a 3 x 8 size table:
+     * <pre>
+     * 0 0 0
+     * 0 0 1
+     * 0 1 0
+     * 0 1 1
+     * 1 0 0
+     * 1 0 1
+     * 1 1 0
+     * 1 1 1
+     * </pre>
+     * @param terms the {@link List} of term strings.
+     * @return a two-dimensional array of bytes representing the truth table
+     * inputs.  The table will be of size: [termNumber] x [2 ^ termNumber]
+     */
+    public static byte[][] createTruthTableInputs(final List<String> terms) {
+        return createTruthTableInputs(terms.size());
+    }
+
+    /**
+     * Creates the inputs needed to populate a truth table based on the provided
+     * number of terms that the expression uses. So, entering 3 for the number
+     * of terms will create a 3 x 8 size table:
+     * <pre>
+     * 0 0 0
+     * 0 0 1
+     * 0 1 0
+     * 0 1 1
+     * 1 0 0
+     * 1 0 1
+     * 1 1 0
+     * 1 1 1
+     * </pre>
+     * @param termNumber the number of terms.
+     * @return a two-dimensional array of bytes representing the truth table
+     * inputs.  The table will be of size: [termNumber] x [2 ^ termNumber]
+     */
+    public static byte[][] createTruthTableInputs(final int termNumber) {
+        final int numColumns = termNumber;
+        final int numRows = (int) Math.pow(2, numColumns);
+        final byte[][] truthTable = new byte[numRows][numColumns];
+
+        for (int row = 0; row < numRows; row++) {
+            for (int col = 0; col < numColumns; col++) {
+                // We're starting from the top-left and going right then down to
+                // the next row. The left-side is of a higher order than the
+                // right-side so adjust accordingly.
+                final int digitOrderPosition = numColumns - 1 - col;
+                final int power = (int) Math.pow(2, digitOrderPosition);
+                final int toggle = (row / power) % 2;
+                truthTable[row][col] = (byte) toggle;
+            }
+        }
+
+        log.trace("Truth table inputs: " + Arrays.deepToString(truthTable));
+
+        return truthTable;
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/cc1cc712/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/util/DocumentVisibilityConversionException.java
----------------------------------------------------------------------
diff --git a/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/util/DocumentVisibilityConversionException.java b/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/util/DocumentVisibilityConversionException.java
new file mode 100644
index 0000000..18111ee
--- /dev/null
+++ b/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/util/DocumentVisibilityConversionException.java
@@ -0,0 +1,62 @@
+/*
+ * 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.rya.mongodb.document.util;
+
+/**
+ * Exception thrown when document visibility conversion encounters a problem.
+ */
+public class DocumentVisibilityConversionException extends Exception {
+    private static final long serialVersionUID = 1L;
+
+    /**
+     * Creates a new instance of {@link DocumentVisibilityConversionException} with no
+     * detail message.
+     */
+    public DocumentVisibilityConversionException() {
+        super();
+    }
+
+    /**
+     * Creates a new instance of {@link DocumentVisibilityConversionException} with the
+     * specified detail message.
+     * @param message the detail message.
+     */
+    public DocumentVisibilityConversionException(final String message) {
+        super(message);
+    }
+
+    /**
+     * Creates a new instance of {@link DocumentVisibilityConversionException} with the
+     * specified detail message and cause.
+     * @param message the detail message.
+     * @param cause the {@link Throwable} cause.
+     */
+    public DocumentVisibilityConversionException(final String message, final Throwable cause) {
+        super(message, cause);
+    }
+
+    /**
+     * Creates a new instance of {@link DocumentVisibilityConversionException} with the
+     * specified cause.
+     * @param cause the {@link Throwable} cause.
+     */
+    public DocumentVisibilityConversionException(final Throwable cause) {
+        super(cause);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/cc1cc712/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/util/DocumentVisibilityUtil.java
----------------------------------------------------------------------
diff --git a/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/util/DocumentVisibilityUtil.java b/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/util/DocumentVisibilityUtil.java
new file mode 100644
index 0000000..8044dfd
--- /dev/null
+++ b/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/util/DocumentVisibilityUtil.java
@@ -0,0 +1,331 @@
+/*
+ * 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.rya.mongodb.document.util;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import org.apache.accumulo.core.data.ByteSequence;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.accumulo.core.security.ColumnVisibility.Node;
+import org.apache.accumulo.core.security.ColumnVisibility.NodeType;
+import org.apache.accumulo.core.security.VisibilityEvaluator;
+import org.apache.accumulo.core.security.VisibilityParseException;
+import org.apache.log4j.Logger;
+import org.apache.rya.mongodb.MongoDbRdfConstants;
+import org.apache.rya.mongodb.document.visibility.DocumentVisibility;
+
+import com.google.common.base.Charsets;
+import com.google.common.collect.Lists;
+import com.mongodb.BasicDBList;
+
+/**
+ * Utility methods for converting boolean expressions between a string
+ * representation to a MongoDB-friendly multidimensional array form that can be
+ * used in MongoDB's aggregation set operations.
+ */
+public final class DocumentVisibilityUtil {
+    private static final Logger log = Logger.getLogger(DocumentVisibilityUtil.class);
+
+    /**
+     * Private constructor to prevent instantiation.
+     */
+    private DocumentVisibilityUtil() {
+    }
+
+    /**
+     * Converts a boolean string expression into a multidimensional
+     * array representation of the boolean expression.
+     * @param booleanString the boolean string expression.
+     * @return the multidimensional array representation of the boolean
+     * expression.
+     * @throws DocumentVisibilityConversionException
+     */
+    public static Object[] toMultidimensionalArray(final String booleanString) throws DocumentVisibilityConversionException {
+        final DocumentVisibility dv = new DocumentVisibility(booleanString);
+        return toMultidimensionalArray(dv);
+    }
+
+    /**
+     * Converts a {@link DocumentVisibility} object into a multidimensional
+     * array representation of the boolean expression.
+     * @param dv the {@link DocumentVisibility}. (not {@code null})
+     * @return the multidimensional array representation of the boolean
+     * expression.
+     * @throws DocumentVisibilityConversionException
+     */
+    public static Object[] toMultidimensionalArray(final DocumentVisibility dv) throws DocumentVisibilityConversionException {
+        checkNotNull(dv);
+        final byte[] expression = dv.flatten();
+        final DocumentVisibility flattenedDv = DisjunctiveNormalFormConverter.createDnfDocumentVisibility(expression);
+        final Object[] result = toMultidimensionalArray(flattenedDv.getParseTree(), flattenedDv.getExpression());
+        // If there's only one group then make sure it's wrapped as an array.
+        // (i.e. "A" should be ["A"])
+        if (result.length > 0 && result[0] instanceof String) {
+            final List<Object[]> formattedResult = new ArrayList<>();
+            formattedResult.add(result);
+            return formattedResult.toArray(new Object[0]);
+        }
+        return result;
+    }
+
+    /**
+     * Converts a {@link Node} and its corresponding expression into a
+     * multidimensional array representation of the boolean expression.
+     * @param node the {@link Node}. (not {@code null})
+     * @param expression the expression byte array.
+     * @return the multidimensional array representation of the boolean
+     * expression.
+     * @throws DocumentVisibilityConversionException
+     */
+    public static Object[] toMultidimensionalArray(final Node node, final byte[] expression) throws DocumentVisibilityConversionException {
+        checkNotNull(node);
+        final List<Object> array = new ArrayList<>();
+
+        if (node.getChildren().isEmpty() && node.getType() == NodeType.TERM) {
+            final String data = getTermNodeData(node, expression);
+            array.add(data);
+        }
+
+        log.trace("Children size: " + node.getChildren().size() + " Type: " + node.getType());
+        for (final Node child : node.getChildren()) {
+            switch (child.getType()) {
+                case EMPTY:
+                case TERM:
+                    String data;
+                    if (child.getType() == NodeType.TERM) {
+                        data = getTermNodeData(child, expression);
+                    } else {
+                        data = "";
+                    }
+                    if (node.getType() == NodeType.OR) {
+                        array.add(Lists.newArrayList(data).toArray(new Object[0]));
+                    } else {
+                        array.add(data);
+                    }
+                    break;
+                case OR:
+                case AND:
+                    array.add(toMultidimensionalArray(child, expression));
+                    break;
+                default:
+                    throw new DocumentVisibilityConversionException("Unknown type: " + child.getType());
+            }
+        }
+
+        return array.toArray(new Object[0]);
+    }
+
+    public static String nodeToBooleanString(final Node node, final byte[] expression) throws DocumentVisibilityConversionException {
+        boolean isFirst = true;
+        final StringBuilder sb = new StringBuilder();
+        if (node.getType() == NodeType.TERM) {
+            final String data = getTermNodeData(node, expression);
+            sb.append(data);
+        }
+        if (node.getType() == NodeType.AND) {
+            sb.append("(");
+        }
+        for (final Node child : node.getChildren()) {
+            if (isFirst) {
+                isFirst = false;
+            } else {
+                if (node.getType() == NodeType.OR) {
+                    sb.append("|");
+                } else if (node.getType() == NodeType.AND) {
+                    sb.append("&");
+                }
+            }
+            switch (child.getType()) {
+                case EMPTY:
+                    sb.append("");
+                    break;
+                case TERM:
+                    final String data = getTermNodeData(child, expression);
+                    sb.append(data);
+                    break;
+                case OR:
+                    sb.append("(");
+                    sb.append(nodeToBooleanString(child, expression));
+                    sb.append(")");
+                    break;
+                case AND:
+                    sb.append(nodeToBooleanString(child, expression));
+                    break;
+                default:
+                    throw new DocumentVisibilityConversionException("Unknown type: " + child.getType());
+            }
+        }
+        if (node.getType() == NodeType.AND) {
+            sb.append(")");
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Converts a multidimensional array object representation of the document
+     * visibility boolean expression into a string.
+     * @param object the multidimensional array object representing the
+     * document visibility boolean expression.
+     * @return the boolean string expression.
+     */
+    public static String multidimensionalArrayToBooleanString(final Object[] object) {
+        final String booleanString = multidimensionalArrayToBooleanStringInternal(object);
+
+        // Simplify and clean up the formatting.
+        final DocumentVisibility dv = DisjunctiveNormalFormConverter.createDnfDocumentVisibility(booleanString);
+        final byte[] bytes = dv.flatten();
+        final String result = new String(bytes, Charsets.UTF_8);
+
+        return result;
+    }
+
+    private static String multidimensionalArrayToBooleanStringInternal(final Object[] object) {
+        final StringBuilder sb = new StringBuilder();
+
+        int count = 0;
+        boolean isAnd = false;
+        for (final Object child : object) {
+            if (child instanceof String) {
+                isAnd = true;
+                if (count > 0) {
+                    sb.append("&");
+                }
+                sb.append(child);
+            } else if (child instanceof Object[]) {
+                if (count > 0 && isAnd) {
+                    sb.append("&");
+                }
+                final Object[] obj = (Object[]) child;
+                sb.append("(");
+                sb.append(multidimensionalArrayToBooleanStringInternal(obj));
+                sb.append(")");
+            }
+
+            if (object.length > 1 && count + 1 < object.length && !isAnd) {
+                sb.append("|");
+            }
+            count++;
+        }
+
+        return sb.toString();
+    }
+
+    /**
+     * Conditionally adds quotes around a string.
+     * @param data the string to add quotes to.
+     * @param addQuotes {@code true} to add quotes. {@code false} to leave the
+     * string as is.
+     * @return the quoted string if {@code addQuotes} is {@code true}.
+     * Otherwise, returns the string as is.
+     */
+    public static String addQuotes(final String data, final boolean addQuotes) {
+        if (addQuotes) {
+            return "\"" + data + "\"";
+        } else {
+            return data;
+        }
+    }
+
+    /**
+     * Returns the term node's data.
+     * @param node the {@link Node}.
+     * @return the term node's data.
+     */
+    public static String getTermNodeData(final Node node, final byte[] expression) {
+        final boolean isQuotedTerm = expression[node.getTermStart()] == '"';
+        final ByteSequence bs = node.getTerm(expression);
+        final String data = addQuotes(new String(bs.toArray(), Charsets.UTF_8), isQuotedTerm);
+        return data;
+    }
+
+    /**
+     * Checks if the user's authorizations allows them to have access to the
+     * provided document based on its document visibility.
+     * @param authorizations the {@link Authorizations}.
+     * @param documentVisibility the document visibility byte expression.
+     * @return {@code true} if the user has access to the document.
+     * {@code false} otherwise.
+     */
+    public static boolean doesUserHaveDocumentAccess(final Authorizations authorizations, final byte[] documentVisibilityExpression) {
+        final byte[] expression = documentVisibilityExpression != null ? documentVisibilityExpression : MongoDbRdfConstants.EMPTY_DV.getExpression();
+        final DocumentVisibility documentVisibility = new DocumentVisibility(expression);
+        return doesUserHaveDocumentAccess(authorizations, documentVisibility);
+    }
+
+    /**
+     * Checks if the user's authorizations allows them to have access to the
+     * provided document based on its document visibility.
+     * @param authorizations the {@link Authorizations}.
+     * @param documentVisibility the {@link DocumentVisibility}.
+     * @return {@code true} if the user has access to the document.
+     * {@code false} otherwise.
+     */
+    public static boolean doesUserHaveDocumentAccess(final Authorizations authorizations, final DocumentVisibility documentVisibility) {
+        return doesUserHaveDocumentAccess(authorizations, documentVisibility, true);
+    }
+
+    /**
+     * Checks if the user's authorizations allows them to have access to the
+     * provided document based on its document visibility.
+     * @param authorizations the {@link Authorizations}.
+     * @param documentVisibility the {@link DocumentVisibility}.
+     * @param doesEmptyAccessPass {@code true} if an empty authorization pass
+     * allows access to everything. {@code false} otherwise.
+     * @return {@code true} if the user has access to the document.
+     * {@code false} otherwise.
+     */
+    public static boolean doesUserHaveDocumentAccess(final Authorizations authorizations, final DocumentVisibility documentVisibility, final boolean doesEmptyAccessPass) {
+        final Authorizations userAuths = authorizations != null ? authorizations : MongoDbRdfConstants.ALL_AUTHORIZATIONS;
+        final VisibilityEvaluator visibilityEvaluator = new VisibilityEvaluator(userAuths);
+        boolean accept = false;
+        if (doesEmptyAccessPass && MongoDbRdfConstants.ALL_AUTHORIZATIONS.equals(userAuths)) {
+            accept = true;
+        } else {
+            try {
+                accept = visibilityEvaluator.evaluate(documentVisibility);
+            } catch (final VisibilityParseException e) {
+                log.error("Could not parse document visibility.");
+            }
+        }
+
+        return accept;
+    }
+
+    /**
+     * Converts a {@link BasicDBList} into an array of {@link Object}s.
+     * @param basicDbList the {@link BasicDBList} to convert.
+     * @return the array of {@link Object}s.
+     */
+    public static Object[] convertBasicDBListToObjectArray(final BasicDBList basicDbList) {
+        final List<Object> list = new ArrayList<>();
+        final Object[] array = basicDbList.toArray();
+        for (final Object child : array) {
+            if (child instanceof BasicDBList) {
+                list.add(convertBasicDBListToObjectArray((BasicDBList)child));
+            } else {
+                list.add(child);
+            }
+        }
+        return list.toArray(new Object[0]);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/cc1cc712/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/visibility/DocumentVisibility.java
----------------------------------------------------------------------
diff --git a/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/visibility/DocumentVisibility.java b/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/visibility/DocumentVisibility.java
new file mode 100644
index 0000000..7f30e7f
--- /dev/null
+++ b/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/visibility/DocumentVisibility.java
@@ -0,0 +1,100 @@
+/*
+ * 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.rya.mongodb.document.visibility;
+
+import org.apache.accumulo.core.security.ColumnVisibility;
+import org.apache.hadoop.io.Text;
+
+/**
+ * Validate the document visibility is a valid expression and set the visibility for a Mutation. See {@link DocumentVisibility#DocumentVisibility(byte[])} for the
+ * definition of an expression.
+ *
+ * <p>
+ * The expression is a sequence of characters from the set [A-Za-z0-9_-.] along with the binary operators "&amp;" and "|" indicating that both operands are
+ * necessary, or the either is necessary. The following are valid expressions for visibility:
+ *
+ * <pre>
+ * A
+ * A|B
+ * (A|B)&amp;(C|D)
+ * orange|(red&amp;yellow)
+ * </pre>
+ *
+ * <p>
+ * The following are not valid expressions for visibility:
+ *
+ * <pre>
+ * A|B&amp;C
+ * A=B
+ * A|B|
+ * A&amp;|B
+ * ()
+ * )
+ * dog|!cat
+ * </pre>
+ *
+ * <p>
+ * In addition to the base set of visibilities, any character can be used in the expression if it is quoted. If the quoted term contains '&quot;' or '\', then
+ * escape the character with '\'. The {@link #quote(String)} method can be used to properly quote and escape terms automatically. The following is an example of
+ * a quoted term:
+ *
+ * <pre>
+ * &quot;A#C&quot; &amp; B
+ * </pre>
+ */
+public class DocumentVisibility extends ColumnVisibility {
+    /**
+     * Creates an empty visibility. Normally, elements with empty visibility can be seen by everyone. Though, one could change this behavior with filters.
+     *
+     * @see #DocumentVisibility(String)
+     */
+    public DocumentVisibility() {
+        super();
+    }
+
+    /**
+     * Creates a document visibility for a Mutation.
+     *
+     * @param expression
+     *          An expression of the rights needed to see this mutation. The expression syntax is defined at the class-level documentation
+     */
+    public DocumentVisibility(final String expression) {
+        super(expression);
+    }
+
+    /**
+     * Creates a document visibility for a Mutation.
+     *
+     * @param expression
+     *          visibility expression
+     * @see #DocumentVisibility(String)
+     */
+    public DocumentVisibility(final Text expression) {
+        super(expression);
+    }
+
+    /**
+     * Creates a document visibility for a Mutation from a string already encoded in UTF-8 bytes.
+     *
+     * @param expression
+     *          visibility expression, encoded as UTF-8 bytes
+     * @see #DocumentVisibility(String)
+     */
+    public DocumentVisibility(final byte[] expression) {
+        super(expression);
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/cc1cc712/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/visibility/DocumentVisibilityAdapter.java
----------------------------------------------------------------------
diff --git a/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/visibility/DocumentVisibilityAdapter.java b/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/visibility/DocumentVisibilityAdapter.java
new file mode 100644
index 0000000..50dc311
--- /dev/null
+++ b/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/document/visibility/DocumentVisibilityAdapter.java
@@ -0,0 +1,143 @@
+/**
+ * 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.rya.mongodb.document.visibility;
+
+import org.apache.log4j.Logger;
+import org.apache.rya.mongodb.MongoDbRdfConstants;
+import org.apache.rya.mongodb.dao.SimpleMongoDBStorageStrategy;
+import org.apache.rya.mongodb.document.util.DocumentVisibilityConversionException;
+import org.apache.rya.mongodb.document.util.DocumentVisibilityUtil;
+
+import com.mongodb.BasicDBList;
+import com.mongodb.BasicDBObject;
+import com.mongodb.BasicDBObjectBuilder;
+import com.mongodb.DBObject;
+
+import edu.umd.cs.findbugs.annotations.DefaultAnnotation;
+import edu.umd.cs.findbugs.annotations.NonNull;
+
+/**
+ * Serializes the document visibility field of a Rya Statement for use in
+ * MongoDB.
+ * The {@link DBObject} will look like:
+ * <pre>
+ * {@code
+ * {
+ *   "documentVisibility": &lt;array&gt;,
+ * }
+ * </pre>
+ */
+@DefaultAnnotation(NonNull.class)
+public final class DocumentVisibilityAdapter {
+    private static final Logger log = Logger.getLogger(DocumentVisibilityAdapter.class);
+
+    public static final String DOCUMENT_VISIBILITY_KEY = SimpleMongoDBStorageStrategy.DOCUMENT_VISIBILITY;
+
+    /**
+     * Private constructor to prevent instantiation.
+     */
+    private DocumentVisibilityAdapter() {
+    }
+
+    /**
+     * Serializes a document visibility expression byte array to a MongoDB
+     * {@link DBObject}.
+     * @param expression the document visibility expression byte array to be
+     * serialized.
+     * @return The MongoDB {@link DBObject}.
+     */
+    public static BasicDBObject toDBObject(final byte[] expression) {
+        DocumentVisibility dv;
+        if (expression == null) {
+            dv = MongoDbRdfConstants.EMPTY_DV;
+        } else {
+            dv = new DocumentVisibility(expression);
+        }
+        return toDBObject(dv);
+    }
+
+    /**
+     * Serializes a {@link DocumentVisibility} to a MongoDB {@link DBObject}.
+     * @param documentVisibility the {@link DocumentVisibility} to be
+     * serialized.
+     * @return The MongoDB {@link DBObject}.
+     */
+    public static BasicDBObject toDBObject(final DocumentVisibility documentVisibility) {
+        DocumentVisibility dv;
+        if (documentVisibility == null) {
+            dv = MongoDbRdfConstants.EMPTY_DV;
+        } else {
+            dv = documentVisibility;
+        }
+        Object[] dvArray = null;
+        try {
+            dvArray = DocumentVisibilityUtil.toMultidimensionalArray(dv);
+        } catch (final DocumentVisibilityConversionException e) {
+            log.error("Unable to convert document visibility");
+        }
+
+        final BasicDBObjectBuilder builder = BasicDBObjectBuilder.start();
+        builder.add(DOCUMENT_VISIBILITY_KEY, dvArray);
+        return (BasicDBObject) builder.get();
+    }
+
+    /**
+     * Deserializes a MongoDB {@link DBObject} to a {@link DocumentVisibility}.
+     * @param mongoObj the {@link DBObject} to be deserialized.
+     * @return the {@link DocumentVisibility} object.
+     * @throws MalformedDocumentVisibilityException
+     */
+    public static DocumentVisibility toDocumentVisibility(final DBObject mongoObj) throws MalformedDocumentVisibilityException {
+        try {
+            final BasicDBObject basicObj = (BasicDBObject) mongoObj;
+
+            final Object documentVisibilityObject = basicObj.get(DOCUMENT_VISIBILITY_KEY);
+            Object[] documentVisibilityArray = null;
+            if (documentVisibilityObject instanceof Object[]) {
+                documentVisibilityArray = (Object[]) documentVisibilityObject;
+            } else if (documentVisibilityObject instanceof BasicDBList) {
+                documentVisibilityArray = DocumentVisibilityUtil.convertBasicDBListToObjectArray((BasicDBList) documentVisibilityObject);
+            }
+
+            final String documentVisibilityString = DocumentVisibilityUtil.multidimensionalArrayToBooleanString(documentVisibilityArray);
+            final DocumentVisibility dv = documentVisibilityString == null ? MongoDbRdfConstants.EMPTY_DV : new DocumentVisibility(documentVisibilityString);
+
+            return dv;
+        } catch(final Exception e) {
+            throw new MalformedDocumentVisibilityException("Failed to make Document Visibility from Mongo Object, it is malformed.", e);
+        }
+    }
+
+    /**
+     * Exception thrown when a MongoDB {@link DBObject} is malformed when
+     * attempting to adapt it into a {@link DocumentVisibility}.
+     */
+    public static class MalformedDocumentVisibilityException extends Exception {
+        private static final long serialVersionUID = 1L;
+
+        /**
+         * Creates a new {@link MalformedDocumentVisibilityException}
+         * @param message - The message to be displayed by the exception.
+         * @param e - The source cause of the exception.
+         */
+        public MalformedDocumentVisibilityException(final String message, final Throwable e) {
+            super(message, e);
+        }
+    }
+}
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/cc1cc712/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/iter/RyaStatementBindingSetCursorIterator.java
----------------------------------------------------------------------
diff --git a/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/iter/RyaStatementBindingSetCursorIterator.java b/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/iter/RyaStatementBindingSetCursorIterator.java
index ebe5c3f..4807c4f 100644
--- a/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/iter/RyaStatementBindingSetCursorIterator.java
+++ b/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/iter/RyaStatementBindingSetCursorIterator.java
@@ -1,5 +1,3 @@
-package org.apache.rya.mongodb.iter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -8,9 +6,9 @@ package org.apache.rya.mongodb.iter;
  * 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
@@ -18,108 +16,125 @@ package org.apache.rya.mongodb.iter;
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.rya.mongodb.iter;
 
-
-import info.aduna.iteration.CloseableIteration;
-
+import java.util.ArrayList;
 import java.util.Collection;
 import java.util.Iterator;
+import java.util.List;
 import java.util.Map.Entry;
 
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.log4j.Logger;
 import org.apache.rya.api.RdfCloudTripleStoreUtils;
 import org.apache.rya.api.domain.RyaStatement;
 import org.apache.rya.api.persist.RyaDAOException;
 import org.apache.rya.mongodb.dao.MongoDBStorageStrategy;
-
+import org.apache.rya.mongodb.document.operators.aggregation.AggregationUtil;
 import org.openrdf.query.BindingSet;
 
 import com.google.common.collect.Multimap;
+import com.mongodb.AggregationOutput;
+import com.mongodb.BasicDBObject;
 import com.mongodb.DBCollection;
-import com.mongodb.DBCursor;
 import com.mongodb.DBObject;
 
-public class RyaStatementBindingSetCursorIterator implements CloseableIteration<Entry<RyaStatement, BindingSet>, RyaDAOException> {
+import info.aduna.iteration.CloseableIteration;
 
-	private DBCollection coll;
-	private Multimap<DBObject, BindingSet> rangeMap;
-	private Iterator<DBObject> queryIterator;
-	private Long maxResults;
-	private DBCursor resultCursor;
-	private RyaStatement currentStatement;
-	private Collection<BindingSet> currentBindingSetCollection;
-	private Iterator<BindingSet> currentBindingSetIterator;
-	private MongoDBStorageStrategy strategy;
-
-	public RyaStatementBindingSetCursorIterator(DBCollection coll,
-			Multimap<DBObject, BindingSet> rangeMap, MongoDBStorageStrategy strategy) {
-		this.coll = coll;
-		this.rangeMap = rangeMap;
-		this.queryIterator = rangeMap.keySet().iterator();
-		this.strategy = strategy;
-	}
-
-	@Override
-	public boolean hasNext() {
-		if (!currentBindingSetIteratorIsValid()) {
-			findNextResult();
-		}
-		return currentBindingSetIteratorIsValid();
-	}
-
-	@Override
-	public Entry<RyaStatement, BindingSet> next() {
-		if (!currentBindingSetIteratorIsValid()) {
-			findNextResult();
-		}
-		if (currentBindingSetIteratorIsValid()) {
-			BindingSet currentBindingSet = currentBindingSetIterator.next();
-			return new RdfCloudTripleStoreUtils.CustomEntry<RyaStatement, BindingSet>(currentStatement, currentBindingSet);
-		}
-		return null;
-	}
-	
-	private boolean currentBindingSetIteratorIsValid() {
-		return (currentBindingSetIterator != null) && currentBindingSetIterator.hasNext();
-	}
-
-	private void findNextResult() {
-		if (!currentResultCursorIsValid()) {
-			findNextValidResultCursor();
-		}
-		if (currentResultCursorIsValid()) {
-			// convert to Rya Statement
-			DBObject queryResult = resultCursor.next();
-			currentStatement = strategy.deserializeDBObject(queryResult);
-			currentBindingSetIterator = currentBindingSetCollection.iterator();
-		}
-	}
-
-	private void findNextValidResultCursor() {
-		while (queryIterator.hasNext()){
-			DBObject currentQuery = queryIterator.next();
-			resultCursor = coll.find(currentQuery);
-			currentBindingSetCollection = rangeMap.get(currentQuery);
-			if (resultCursor.hasNext()) return;
-		}
-	}
-	
-	private boolean currentResultCursorIsValid() {
-		return (resultCursor != null) && resultCursor.hasNext();
-	}
-
-
-	public void setMaxResults(Long maxResults) {
-		this.maxResults = maxResults;
-	}
-
-	@Override
-	public void close() throws RyaDAOException {
-		// TODO don't know what to do here
-	}
-
-	@Override
-	public void remove() throws RyaDAOException {
-		next();
-	}
+public class RyaStatementBindingSetCursorIterator implements CloseableIteration<Entry<RyaStatement, BindingSet>, RyaDAOException> {
+    private static final Logger log = Logger.getLogger(RyaStatementBindingSetCursorIterator.class);
+
+    private final DBCollection coll;
+    private final Multimap<DBObject, BindingSet> rangeMap;
+    private final Iterator<DBObject> queryIterator;
+    private Long maxResults;
+    private Iterator<DBObject> resultsIterator;
+    private RyaStatement currentStatement;
+    private Collection<BindingSet> currentBindingSetCollection;
+    private Iterator<BindingSet> currentBindingSetIterator;
+    private final MongoDBStorageStrategy<RyaStatement> strategy;
+    private final Authorizations auths;
+
+    public RyaStatementBindingSetCursorIterator(final DBCollection coll,
+            final Multimap<DBObject, BindingSet> rangeMap, final MongoDBStorageStrategy<RyaStatement> strategy, final Authorizations auths) {
+        this.coll = coll;
+        this.rangeMap = rangeMap;
+        this.queryIterator = rangeMap.keySet().iterator();
+        this.strategy = strategy;
+        this.auths = auths;
+    }
+
+    @Override
+    public boolean hasNext() {
+        if (!currentBindingSetIteratorIsValid()) {
+            findNextResult();
+        }
+        return currentBindingSetIteratorIsValid();
+    }
+
+    @Override
+    public Entry<RyaStatement, BindingSet> next() {
+        if (!currentBindingSetIteratorIsValid()) {
+            findNextResult();
+        }
+        if (currentBindingSetIteratorIsValid()) {
+            final BindingSet currentBindingSet = currentBindingSetIterator.next();
+            return new RdfCloudTripleStoreUtils.CustomEntry<RyaStatement, BindingSet>(currentStatement, currentBindingSet);
+        }
+        return null;
+    }
+
+    private boolean currentBindingSetIteratorIsValid() {
+        return (currentBindingSetIterator != null) && currentBindingSetIterator.hasNext();
+    }
+
+    private void findNextResult() {
+        if (!currentResultCursorIsValid()) {
+            findNextValidResultCursor();
+        }
+        if (currentResultCursorIsValid()) {
+            // convert to Rya Statement
+            final DBObject queryResult = resultsIterator.next();
+            currentStatement = strategy.deserializeDBObject(queryResult);
+            currentBindingSetIterator = currentBindingSetCollection.iterator();
+        }
+    }
+
+    private void findNextValidResultCursor() {
+        while (queryIterator.hasNext()){
+            final DBObject currentQuery = queryIterator.next();
+            currentBindingSetCollection = rangeMap.get(currentQuery);
+            // Executing redact aggregation to only return documents the user
+            // has access to.
+            final List<DBObject> pipeline = new ArrayList<>();
+            pipeline.add(new BasicDBObject("$match", currentQuery));
+            pipeline.addAll(AggregationUtil.createRedactPipeline(auths));
+            log.debug(pipeline);
+            final AggregationOutput output = coll.aggregate(pipeline);
+            resultsIterator = output.results().iterator();
+            if (resultsIterator.hasNext()) {
+                break;
+            }
+        }
+    }
+
+    private boolean currentResultCursorIsValid() {
+        return (resultsIterator != null) && resultsIterator.hasNext();
+    }
+
+
+    public void setMaxResults(final Long maxResults) {
+        this.maxResults = maxResults;
+    }
+
+    @Override
+    public void close() throws RyaDAOException {
+        // TODO don't know what to do here
+    }
+
+    @Override
+    public void remove() throws RyaDAOException {
+        next();
+    }
 
 }

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/cc1cc712/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/iter/RyaStatementCursorIterator.java
----------------------------------------------------------------------
diff --git a/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/iter/RyaStatementCursorIterator.java b/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/iter/RyaStatementCursorIterator.java
index 9bb5d38..2f6fd44 100644
--- a/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/iter/RyaStatementCursorIterator.java
+++ b/dao/mongodb.rya/src/main/java/org/apache/rya/mongodb/iter/RyaStatementCursorIterator.java
@@ -1,5 +1,3 @@
-package org.apache.rya.mongodb.iter;
-
 /*
  * Licensed to the Apache Software Foundation (ASF) under one
  * or more contributor license agreements.  See the NOTICE file
@@ -8,9 +6,9 @@ package org.apache.rya.mongodb.iter;
  * 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
@@ -18,87 +16,100 @@ package org.apache.rya.mongodb.iter;
  * specific language governing permissions and limitations
  * under the License.
  */
+package org.apache.rya.mongodb.iter;
 
-
-import info.aduna.iteration.CloseableIteration;
-
+import java.util.ArrayList;
 import java.util.Iterator;
-import java.util.Map.Entry;
+import java.util.List;
 import java.util.Set;
 
-import org.apache.rya.api.RdfCloudTripleStoreUtils;
+import org.apache.accumulo.core.security.Authorizations;
+import org.apache.log4j.Logger;
 import org.apache.rya.api.domain.RyaStatement;
 import org.apache.rya.api.persist.RyaDAOException;
 import org.apache.rya.mongodb.dao.MongoDBStorageStrategy;
+import org.apache.rya.mongodb.document.operators.aggregation.AggregationUtil;
 
-import org.calrissian.mango.collect.CloseableIterable;
-import org.openrdf.query.BindingSet;
-
+import com.mongodb.AggregationOutput;
+import com.mongodb.BasicDBObject;
 import com.mongodb.DBCollection;
-import com.mongodb.DBCursor;
 import com.mongodb.DBObject;
 
-public class RyaStatementCursorIterator implements CloseableIteration<RyaStatement, RyaDAOException> {
-
-	private DBCollection coll;
-	private Iterator<DBObject> queryIterator;
-	private DBCursor currentCursor;
-	private MongoDBStorageStrategy strategy;
-	private Long maxResults;
-
-	public RyaStatementCursorIterator(DBCollection coll, Set<DBObject> queries, MongoDBStorageStrategy strategy) {
-		this.coll = coll;
-		this.queryIterator = queries.iterator();
-		this.strategy = strategy;
-	}
-
-	@Override
-	public boolean hasNext() {
-		if (!currentCursorIsValid()) {
-			findNextValidCursor();
-		}
-		return currentCursorIsValid();
-	}
-
-	@Override
-	public RyaStatement next() {
-		if (!currentCursorIsValid()) {
-			findNextValidCursor();
-		}
-		if (currentCursorIsValid()) {
-			// convert to Rya Statement
-			DBObject queryResult = currentCursor.next();
-			RyaStatement statement = strategy.deserializeDBObject(queryResult);
-			return statement;
-		}
-		return null;
-	}
-	
-	private void findNextValidCursor() {
-		while (queryIterator.hasNext()){
-			DBObject currentQuery = queryIterator.next();
-			currentCursor = coll.find(currentQuery);
-			if (currentCursor.hasNext()) break;
-		}
-	}
-	
-	private boolean currentCursorIsValid() {
-		return (currentCursor != null) && currentCursor.hasNext();
-	}
-
-
-	public void setMaxResults(Long maxResults) {
-		this.maxResults = maxResults;
-	}
-
-	@Override
-	public void close() throws RyaDAOException {
-		// TODO don't know what to do here
-	}
-
-	@Override
-	public void remove() throws RyaDAOException {
-		next();
-	}
+import info.aduna.iteration.CloseableIteration;
 
+public class RyaStatementCursorIterator implements CloseableIteration<RyaStatement, RyaDAOException> {
+    private static final Logger log = Logger.getLogger(RyaStatementCursorIterator.class);
+
+    private final DBCollection coll;
+    private final Iterator<DBObject> queryIterator;
+    private Iterator<DBObject> resultsIterator;
+    private final MongoDBStorageStrategy<RyaStatement> strategy;
+    private Long maxResults;
+    private final Authorizations auths;
+
+    public RyaStatementCursorIterator(final DBCollection coll, final Set<DBObject> queries, final MongoDBStorageStrategy<RyaStatement> strategy, final Authorizations auths) {
+        this.coll = coll;
+        this.queryIterator = queries.iterator();
+        this.strategy = strategy;
+        this.auths = auths;
+    }
+
+    @Override
+    public boolean hasNext() {
+        if (!currentCursorIsValid()) {
+            findNextValidCursor();
+        }
+        return currentCursorIsValid();
+    }
+
+    @Override
+    public RyaStatement next() {
+        if (!currentCursorIsValid()) {
+            findNextValidCursor();
+        }
+        if (currentCursorIsValid()) {
+            // convert to Rya Statement
+            final DBObject queryResult = resultsIterator.next();
+            final RyaStatement statement = strategy.deserializeDBObject(queryResult);
+            return statement;
+        }
+        return null;
+    }
+
+    private void findNextValidCursor() {
+        while (queryIterator.hasNext()){
+            final DBObject currentQuery = queryIterator.next();
+
+            // Executing redact aggregation to only return documents the user
+            // has access to.
+            final List<DBObject> pipeline = new ArrayList<>();
+            pipeline.add(new BasicDBObject("$match", currentQuery));
+            pipeline.addAll(AggregationUtil.createRedactPipeline(auths));
+            log.debug(pipeline);
+            final AggregationOutput output = coll.aggregate(pipeline);
+            resultsIterator = output.results().iterator();
+            if (resultsIterator.hasNext()) {
+                break;
+            }
+        }
+    }
+
+    private boolean currentCursorIsValid() {
+        return (resultsIterator != null) && resultsIterator.hasNext();
+    }
+
+
+    public void setMaxResults(final Long maxResults) {
+        this.maxResults = maxResults;
+    }
+
+    @Override
+    public void close() throws RyaDAOException {
+        // TODO don't know what to do here
+    }
+
+    @Override
+    public void remove() throws RyaDAOException {
+        next();
+    }
 }

http://git-wip-us.apache.org/repos/asf/incubator-rya/blob/cc1cc712/dao/mongodb.rya/src/test/java/org/apache/rya/mongodb/MongoDBRyaDAOIT.java
----------------------------------------------------------------------
diff --git a/dao/mongodb.rya/src/test/java/org/apache/rya/mongodb/MongoDBRyaDAOIT.java b/dao/mongodb.rya/src/test/java/org/apache/rya/mongodb/MongoDBRyaDAOIT.java
index b4f7819..c862815 100644
--- a/dao/mongodb.rya/src/test/java/org/apache/rya/mongodb/MongoDBRyaDAOIT.java
+++ b/dao/mongodb.rya/src/test/java/org/apache/rya/mongodb/MongoDBRyaDAOIT.java
@@ -18,25 +18,32 @@ package org.apache.rya.mongodb;
  * under the License.
  */
 
+import static org.apache.rya.mongodb.dao.SimpleMongoDBStorageStrategy.DOCUMENT_VISIBILITY;
 import static org.apache.rya.mongodb.dao.SimpleMongoDBStorageStrategy.TIMESTAMP;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertTrue;
 
 import java.io.IOException;
 
+import org.apache.accumulo.core.security.Authorizations;
 import org.apache.hadoop.conf.Configuration;
 import org.apache.rya.api.RdfCloudTripleStoreConfiguration;
 import org.apache.rya.api.domain.RyaStatement;
 import org.apache.rya.api.domain.RyaStatement.RyaStatementBuilder;
 import org.apache.rya.api.domain.RyaURI;
 import org.apache.rya.api.persist.RyaDAOException;
+import org.apache.rya.api.persist.query.RyaQuery;
+import org.apache.rya.mongodb.document.util.AuthorizationsUtil;
+import org.apache.rya.mongodb.document.visibility.DocumentVisibility;
+import org.bson.Document;
+import org.calrissian.mango.collect.CloseableIterable;
 import org.junit.Before;
 import org.junit.Test;
 
-import com.mongodb.DB;
-import com.mongodb.DBCollection;
-import com.mongodb.DBObject;
 import com.mongodb.MongoException;
+import com.mongodb.client.MongoCollection;
+import com.mongodb.client.MongoDatabase;
 
 public class MongoDBRyaDAOIT extends MongoRyaTestBase {
 
@@ -45,40 +52,43 @@ public class MongoDBRyaDAOIT extends MongoRyaTestBase {
 
     @Before
     public void setUp() throws IOException, RyaDAOException{
-           final Configuration conf = new Configuration();
-            conf.set(MongoDBRdfConfiguration.MONGO_DB_NAME, "test");
-            conf.set(MongoDBRdfConfiguration.MONGO_COLLECTION_PREFIX, "rya_");
-            conf.set(RdfCloudTripleStoreConfiguration.CONF_TBL_PREFIX, "rya_");
-            configuration = new MongoDBRdfConfiguration(conf);
-            final int port = mongoClient.getServerAddressList().get(0).getPort();
-            configuration.set(MongoDBRdfConfiguration.MONGO_INSTANCE_PORT, Integer.toString(port));
-            dao = new MongoDBRyaDAO(configuration, mongoClient);
+        final Configuration conf = new Configuration();
+        conf.set(MongoDBRdfConfiguration.MONGO_DB_NAME, "test");
+        conf.set(MongoDBRdfConfiguration.MONGO_COLLECTION_PREFIX, "rya_");
+        conf.set(RdfCloudTripleStoreConfiguration.CONF_TBL_PREFIX, "rya_");
+        configuration = new MongoDBRdfConfiguration(conf);
+        configuration.setAuths("A", "B", "C");
+        final int port = mongoClient.getServerAddressList().get(0).getPort();
+        configuration.set(MongoDBRdfConfiguration.MONGO_INSTANCE_PORT, Integer.toString(port));
+        dao = new MongoDBRyaDAO(configuration, mongoClient);
     }
 
     @Test
     public void testDeleteWildcard() throws RyaDAOException {
         final RyaStatementBuilder builder = new RyaStatementBuilder();
         builder.setPredicate(new RyaURI("http://temp.com"));
+        builder.setColumnVisibility(new DocumentVisibility("A").flatten());
         dao.delete(builder.build(), configuration);
     }
 
-
     @Test
     public void testAdd() throws RyaDAOException, MongoException, IOException {
         final RyaStatementBuilder builder = new RyaStatementBuilder();
         builder.setPredicate(new RyaURI("http://temp.com"));
         builder.setSubject(new RyaURI("http://subject.com"));
         builder.setObject(new RyaURI("http://object.com"));
+        builder.setColumnVisibility(new DocumentVisibility("B").flatten());
 
-        final DB db = mongoClient.getDB(configuration.get(MongoDBRdfConfiguration.MONGO_DB_NAME));
-        final DBCollection coll = db.getCollection(configuration.getTriplesCollectionName());
+        final MongoDatabase db = mongoClient.getDatabase(configuration.get(MongoDBRdfConfiguration.MONGO_DB_NAME));
+        final MongoCollection<Document> coll = db.getCollection(configuration.getTriplesCollectionName());
 
         dao.add(builder.build());
 
         assertEquals(coll.count(),1);
 
-        final DBObject dbo = coll.findOne();
-        assertTrue(dbo.containsField(TIMESTAMP));
+        final Document dbo = coll.find().first();
+        assertTrue(dbo.containsKey(DOCUMENT_VISIBILITY));
+        assertTrue(dbo.containsKey(TIMESTAMP));
     }
 
     @Test
@@ -87,9 +97,10 @@ public class MongoDBRyaDAOIT extends MongoRyaTestBase {
         builder.setPredicate(new RyaURI("http://temp.com"));
         builder.setSubject(new RyaURI("http://subject.com"));
         builder.setObject(new RyaURI("http://object.com"));
+        builder.setColumnVisibility(new DocumentVisibility("C").flatten());
         final RyaStatement statement = builder.build();
-        final DB db = mongoClient.getDB(configuration.get(MongoDBRdfConfiguration.MONGO_DB_NAME));
-        final DBCollection coll = db.getCollection(configuration.getTriplesCollectionName());
+        final MongoDatabase db = mongoClient.getDatabase(configuration.get(MongoDBRdfConfiguration.MONGO_DB_NAME));
+        final MongoCollection<Document> coll = db.getCollection(configuration.getTriplesCollectionName());
 
         dao.add(statement);
 
@@ -108,10 +119,11 @@ public class MongoDBRyaDAOIT extends MongoRyaTestBase {
         builder.setSubject(new RyaURI("http://subject.com"));
         builder.setObject(new RyaURI("http://object.com"));
         builder.setContext(new RyaURI("http://context.com"));
+        builder.setColumnVisibility(new DocumentVisibility("A&B&C").flatten());
         final RyaStatement statement = builder.build();
 
-        final DB db = mongoClient.getDB(configuration.get(MongoDBRdfConfiguration.MONGO_DB_NAME));
-        final DBCollection coll = db.getCollection(configuration.getTriplesCollectionName());
+        final MongoDatabase db = mongoClient.getDatabase(configuration.get(MongoDBRdfConfiguration.MONGO_DB_NAME));
+        final MongoCollection<Document> coll = db.getCollection(configuration.getTriplesCollectionName());
 
         dao.add(statement);
 
@@ -127,4 +139,406 @@ public class MongoDBRyaDAOIT extends MongoRyaTestBase {
 
         assertEquals(coll.count(),1);
     }
+
+    @Test
+    public void testVisibility() throws RyaDAOException, MongoException, IOException {
+        // Doc requires "A" and user has "B" = User CANNOT view
+        assertFalse(testVisibilityStatement("A", new Authorizations("B")));
+
+        // Doc requires "A" and user has "A" = User can view
+        assertTrue(testVisibilityStatement("A", new Authorizations("A")));
+
+        // Doc requires "A" and "B" and user has "A" and "B" = User can view
+        assertTrue(testVisibilityStatement("A&B", new Authorizations("A", "B")));
+
+        // Doc requires "A" or "B" and user has "A" and "B" = User can view
+        assertTrue(testVisibilityStatement("A|B", new Authorizations("A", "B")));
+
+        // Doc requires "A" and user has "A" and "B" = User can view
+        assertTrue(testVisibilityStatement("A", new Authorizations("A", "B")));
+
+        // Doc requires "A" and user has "A" and "B" and "C" = User can view
+        assertTrue(testVisibilityStatement("A", new Authorizations("A", "B", "C")));
+
+        // Doc requires "A" and "B" and user has "A" = User CANNOT view
+        assertFalse(testVisibilityStatement("A&B", new Authorizations("A")));
+
+        // Doc requires "A" and "B" and user has "B" = User CANNOT view
+        assertFalse(testVisibilityStatement("A&B", new Authorizations("B")));
+
+        // Doc requires "A" and "B" and user has "C" = User CANNOT view
+        assertFalse(testVisibilityStatement("A&B", new Authorizations("C")));
+
+        // Doc requires "A" and "B" and "C" and user has "A" and "B" and "C" = User can view
+        assertTrue(testVisibilityStatement("A&B&C", new Authorizations("A", "B", "C")));
+
+        // Doc requires "A" and "B" and "C" and user has "A" and "B" = User CANNOT view
+        assertFalse(testVisibilityStatement("A&B&C", new Authorizations("A", "B")));
+
+        // Doc requires "A" and "B" and "C" and user has "A" = User CANNOT view
+        assertFalse(testVisibilityStatement("A&B&C", new Authorizations("A")));
+
+        // Doc requires "A" and "B" and "C" and user has "B" = User CANNOT view
+        assertFalse(testVisibilityStatement("A&B&C", new Authorizations("B")));
+
+        // Doc requires "A" and "B" and "C" and user has "C" = User CANNOT view
+        assertFalse(testVisibilityStatement("A&B&C", new Authorizations("C")));
+
+        // Doc requires "A" and "B" and user has "A" and "B" and "C" = User can view
+        assertTrue(testVisibilityStatement("A&B", new Authorizations("A", "B", "C")));
+
+        // Doc requires "A" or "B" and user has "A" = User can view
+        assertTrue(testVisibilityStatement("A|B", new Authorizations("A")));
+
+        // Doc requires "A" or "B" and user has "B" = User can view
+        assertTrue(testVisibilityStatement("A|B", new Authorizations("B")));
+
+        // Doc requires "A" or "B" and user has "C" = User CANNOT view
+        assertFalse(testVisibilityStatement("A|B", new Authorizations("C")));
+
+        // Doc requires "A" or "B" or "C" and user has "A" and "B" and "C" = User can view
+        assertTrue(testVisibilityStatement("A|B|C", new Authorizations("A", "B", "C")));
+
+        // Doc requires "A" or "B" or "C" and user has "A" and "B" = User can view
+        assertTrue(testVisibilityStatement("A|B|C", new Authorizations("A", "B")));
+
+        // Doc requires "A" or "B" or "C" and user has "A" = User can view
+        assertTrue(testVisibilityStatement("A|B|C", new Authorizations("A")));
+
+        // Doc requires "A" or "B" or "C" and user has "B" = User can view
+        assertTrue(testVisibilityStatement("A|B|C", new Authorizations("B")));
+
+        // Doc requires "A" or "B" or "C" and user has "C" = User can view
+        assertTrue(testVisibilityStatement("A|B|C", new Authorizations("C")));
+
+        // Doc requires "A" or "B" and user has "A" and "B" and "C" = User can view
+        assertTrue(testVisibilityStatement("A|B", new Authorizations("A", "B", "C")));
+
+        // Doc requires "A" and user has ALL_AUTHORIZATIONS = User can view
+        assertTrue(testVisibilityStatement("A", MongoDbRdfConstants.ALL_AUTHORIZATIONS));
+
+        // Doc requires "A" and "B" and user has ALL_AUTHORIZATIONS = User can view
+        assertTrue(testVisibilityStatement("A&B", MongoDbRdfConstants.ALL_AUTHORIZATIONS));
+
+        // Doc requires "A" or "B" and user has ALL_AUTHORIZATIONS = User can view
+        assertTrue(testVisibilityStatement("A|B", MongoDbRdfConstants.ALL_AUTHORIZATIONS));
+
+        // Doc has no requirement and user has ALL_AUTHORIZATIONS = User can view
+        assertTrue(testVisibilityStatement("", MongoDbRdfConstants.ALL_AUTHORIZATIONS));
+
+        // Doc has no requirement and user has "A" = User can view
+        assertTrue(testVisibilityStatement("", new Authorizations("A")));
+
+        // Doc has no requirement and user has "A" and "B" = User can view
+        assertTrue(testVisibilityStatement("", new Authorizations("A", "B")));
+
+        // Doc requires "A" or ("B" and "C") and user has "A" = User can view
+        assertTrue(testVisibilityStatement("A|(B&C)", new Authorizations("A")));
+
+        // Doc requires "A" or ("B" and "C") and user has "B" and "C" = User can view
+        assertTrue(testVisibilityStatement("A|(B&C)", new Authorizations("B", "C")));
+
+        // Doc requires "A" or ("B" and "C") and user has "B" = User CANNOT view
+        assertFalse(testVisibilityStatement("A|(B&C)", new Authorizations("B")));
+
+        // Doc requires "A" or ("B" and "C") and user has "C" = User CANNOT view
+        assertFalse(testVisibilityStatement("A|(B&C)", new Authorizations("C")));
+
+        // Doc requires "A" and ("B" or "C") and user has "A" and "B" = User can view
+        assertTrue(testVisibilityStatement("A&(B|C)", new Authorizations("A", "B")));
+
+        // Doc requires "A" and ("B" or "C") and user has "A" and "B" = User can view
+        assertTrue(testVisibilityStatement("A&(B|C)", new Authorizations("A", "C")));
+
+        // Doc requires "A" and ("B" or "C") and user has "B" and "C" = User CANNOT view
+        assertFalse(testVisibilityStatement("A&(B|C)", new Authorizations("B", "C")));
+
+        // Doc requires "A" and ("B" or "C") and user has "A" = User CANNOT view
+        assertFalse(testVisibilityStatement("A&(B|C)", new Authorizations("A")));
+
+        // Doc requires "A" and ("B" or "C") and user has "B" = User CANNOT view
+        assertFalse(testVisibilityStatement("A&(B|C)", new Authorizations("B")));
+
+        // Doc requires "A" and ("B" or "C") and user has "C" = User can view
+        assertFalse(testVisibilityStatement("A&(B|C)", new Authorizations("C")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "A" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("A")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "B" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("B")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "C" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("C")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "D" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("D")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "E" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("E")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "A" and "B" = User can view
+        assertTrue(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("A", "B")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "C" and "D" = User can view
+        assertTrue(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("C", "D")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "A" and "B" and "E" = User can view
+        assertTrue(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("A", "B", "E")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "C" and "D" and "E" = User can view
+        assertTrue(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("C", "D", "E")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "A" and "C" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("A", "C")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "A" and "D" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("A", "D")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "B" and "C" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("B", "C")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "B" and "D" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("B", "D")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "A" and "B" and "C" = User can view
+        assertTrue(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("A", "B", "C")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "A" and "B" and "C" = User can view
+        assertTrue(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("A", "B", "D")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "A" and "C" and "D" = User can view
+        assertTrue(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("A", "C", "D")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "B" and "C" and "D" = User can view
+        assertTrue(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("B", "C", "D")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "B" and "C" and "D" and "E"= User can view
+        assertTrue(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("B", "C", "D", "E")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "A" and "B" and "C" and "D" = User can view
+        assertTrue(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("A", "B", "C", "D")));
+
+        // Doc requires ("A" and "B") or ("C" and "D") and user has "A" and "B" and "C" and "D" and "E" = User can view
+        assertTrue(testVisibilityStatement("(A&B)|(C&D)", new Authorizations("A", "B", "C", "D", "E")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "A" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("A")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "B" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("B")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "C" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("C")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "D" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("D")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "E" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("E")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "A" and "B" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("A", "B")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "C" and "D" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("C", "D")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "A" and "B" and "E" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("A", "B", "E")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "C" and "D" and "E" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("C", "D", "E")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "A" and "C" = User can view
+        assertTrue(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("A", "C")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "A" and "D" = User can view
+        assertTrue(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("A", "D")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "B" and "C" = User can view
+        assertTrue(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("B", "C")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "B" and "D" = User can view
+        assertTrue(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("B", "D")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "B" and "D" and "E" = User can view
+        assertTrue(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("B", "D", "E")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "A" and "B" and "C" = User can view
+        assertTrue(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("A", "B", "C")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "A" and "B" and "C" = User can view
+        assertTrue(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("A", "B", "D")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "A" and "C" and "D" = User can view
+        assertTrue(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("A", "C", "D")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "B" and "C" and "D" = User can view
+        assertTrue(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("B", "C", "D")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "B" and "C" and "D" and "E"= User can view
+        assertTrue(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("B", "C", "D", "E")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "A" and "B" and "C" and "D" = User can view
+        assertTrue(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("A", "B", "C", "D")));
+
+        // Doc requires ("A" or "B") and ("C" or "D") and user has "A" and "B" and "C" and "D" and "E" = User can view
+        assertTrue(testVisibilityStatement("(A|B)&(C|D)", new Authorizations("A", "B", "C", "D", "E")));
+
+        // Doc requires "(A|B)&(C|(D&E))" and user has "A" and "C" = User can view
+        assertTrue(testVisibilityStatement("(A|B)&(C|(D&E))", new Authorizations("A", "C")));
+
+        // Doc requires "(A|B)&(C|(D&E))" and user has "B" and "C" = User can view
+        assertTrue(testVisibilityStatement("(A|B)&(C|(D&E))", new Authorizations("B", "C")));
+
+        // Doc requires "(A|B)&(C|(D&E))" and user has "A" and "D" and "E" = User can view
+        assertTrue(testVisibilityStatement("(A|B)&(C|(D&E))", new Authorizations("A", "D", "E")));
+
+        // Doc requires "(A|B)&(C|(D&E))" and user has "B" and "D" and "E" = User can view
+        assertTrue(testVisibilityStatement("(A|B)&(C|(D&E))", new Authorizations("B", "D", "E")));
+
+        // Doc requires "(A|B)&(C|(D&E))" and user has "A" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|(D&E))", new Authorizations("A")));
+
+        // Doc requires "(A|B)&(C|(D&E))" and user has "B" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|(D&E))", new Authorizations("B")));
+
+        // Doc requires "(A|B)&(C|(D&E))" and user has "C" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|(D&E))", new Authorizations("C")));
+
+        // Doc requires "(A|B)&(C|(D&E))" and user has "D" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|(D&E))", new Authorizations("D")));
+
+        // Doc requires "(A|B)&(C|(D&E))" and user has "E" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|(D&E))", new Authorizations("E")));
+
+        // Doc requires "(A|B)&(C|(D&E))" and user has "D" and "E" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|(D&E))", new Authorizations("D", "E")));
+
+        // Doc requires "(A|B)&(C|(D&E))" and user has "A" and "D" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|(D&E))", new Authorizations("A", "D")));
+
+        // Doc requires "(A|B)&(C|(D&E))" and user has "B" and "E" = User CANNOT view
+        assertFalse(testVisibilityStatement("(A|B)&(C|(D&E))", new Authorizations("B", "E")));
+
+        // Doc requires "A|(B&C&(D|E))" and user has "A" = User can view
+        assertTrue(testVisibilityStatement("A|(B&C&(D|E))", new Authorizations("A")));
+
+        // Doc requires "A|(B&C&(D|E))" and user has "B" and "C" and "D" = User can view
+        assertTrue(testVisibilityStatement("A|(B&C&(D|E))", new Authorizations("B", "C", "D")));
+
+        // Doc requires "A|(B&C&(D|E))" and user has "B" and "C" and "E" = User can view
+        assertTrue(testVisibilityStatement("A|(B&C&(D|E))", new Authorizations("B", "C", "E")));
+
+        // Doc requires "A|(B&C&(D|E))" and user has "B" = User CANNOT view
+        assertFalse(testVisibilityStatement("A|(B&C&(D|E))", new Authorizations("B")));
+
+        // Doc requires "A|(B&C&(D|E))" and user has "C" = User CANNOT view
+        assertFalse(testVisibilityStatement("A|(B&C&(D|E))", new Authorizations("C")));
+
+        // Doc requires "A|(B&C&(D|E))" and user has "D" = User CANNOT view
+        assertFalse(testVisibilityStatement("A|(B&C&(D|E))", new Authorizations("D")));
+
+        // Doc requires "A|(B&C&(D|E))" and user has "E" = User CANNOT view
+        assertFalse(testVisibilityStatement("A|(B&C&(D|E))", new Authorizations("E")));
+
+        // Doc requires "A|(B&C&(D|E))" and user has "B" and "C" = User CANNOT view
+        assertFalse(testVisibilityStatement("A|(B&C&(D|E))", new Authorizations("B", "C")));
+
+        // Doc requires "A|(B&C&(D|E))" and user has "D" and "E" = User CANNOT view
+        assertFalse(testVisibilityStatement("A|(B&C&(D|E))", new Authorizations("D", "E")));
+
+        // Doc requires "A|B|C|D|(E&F&G&H)" and user has "A" = User can view
+        assertTrue(testVisibilityStatement("A|B|C|D|(E&F&G&H)", new Authorizations("A")));
+
+        // Doc requires "A|B|C|D|(E&F&G&H)" and user has "E" = User CANNOT view
+        assertFalse(testVisibilityStatement("A|B|C|D|(E&F&G&H)", new Authorizations("E")));
+
+        // Doc requires "A|B|C|D|(E&F&G&H)" and user has "E" and "F" = User CANNOT view
+        assertFalse(testVisibilityStatement("A|B|C|D|(E&F&G&H)", new Authorizations("E", "F")));
+
+        // Doc requires "A|B|C|D|(E&F&G&H)" and user has "I" = User CANNOT view
+        assertFalse(testVisibilityStatement("A|B|C|D|(E&F&G&H)", new Authorizations("I")));
+
+        // Doc requires "A|B|C|D|(E&F&G&H)" and user has "A" and "I" = User can view
+        assertTrue(testVisibilityStatement("A|B|C|D|(E&F&G&H)", new Authorizations("A", "I")));
+
+        // Doc requires "A|B|C|D|(E&F&G&H)" and user has "E" and "F" and "G" and "H" = User can view
+        assertTrue(testVisibilityStatement("A|B|C|D|(E&F&G&H)", new Authorizations("E", "F", "G", "H")));
+
+        // Doc requires "A|B|C|D|(E&F&G&H)" and user has "E" and "F" and "G" and "H" and "I" = User can view
+        assertTrue(testVisibilityStatement("A|B|C|D|(E&F&G&H)", new Authorizations("E", "F", "G", "H", "I")));
+
+        // Doc has no requirement and user has ALL_AUTHORIZATIONS = User can view
+        assertTrue(testVisibilityStatement(null, MongoDbRdfConstants.ALL_AUTHORIZATIONS));
+
+        // Doc has no requirement and user has "A" = User can view
+        assertTrue(testVisibilityStatement(null, new Authorizations("A")));
+
+        // Doc has no requirement and user has "A" and "B" = User can view
+        assertTrue(testVisibilityStatement(null, new Authorizations("A", "B")));
+
+        // Doc has no requirement and user has no authorizations = User can view
+        assertTrue(testVisibilityStatement(null, null));
+
+        // Doc has no requirement and user has no authorizations = User can view
+        assertTrue(testVisibilityStatement("", null));
+
+        // Doc requires "A" and user has no authorizations = User can view
+        assertTrue(testVisibilityStatement("A", null));
+
+        // Doc requires "A" and "B" and user has no authorizations = User can view
+        assertTrue(testVisibilityStatement("A&B", null));
+
+        // Doc requires "A" or "B" and user has no authorizations = User can view
+        assertTrue(testVisibilityStatement("A|B", null));
+    }
+
+    /**
+     * Generates a test statement with the provided document visibility to
+     * determine if the specified user authorization can view the statement.
+     * @param documentVisibility the document visibility boolean expression
+     * string.
+     * @param userAuthorizations the user authorization strings.
+     * @return {@code true} if provided authorization could access the document
+     * in the collection. {@code false} otherwise.
+     * @throws RyaDAOException
+     */
+    private boolean testVisibilityStatement(final String documentVisibility, final Authorizations userAuthorizations) throws RyaDAOException {
+        final MongoDatabase db = mongoClient.getDatabase(configuration.get(MongoDBRdfConfiguration.MONGO_DB_NAME));
+        final MongoCollection<Document> coll = db.getCollection(configuration.getTriplesCollectionName());
+
+        final RyaStatement statement = buildVisibilityTestRyaStatement(documentVisibility);
+
+        dao.getConf().setAuths(AuthorizationsUtil.getAuthorizationsStringArray(Authorizations.EMPTY));
+        dao.add(statement);
+        dao.getConf().setAuths(AuthorizationsUtil.getAuthorizationsStringArray(userAuthorizations != null ? userAuthorizations : Authorizations.EMPTY));
+
+        assertEquals(coll.count(), 1);
+
+        final MongoDBQueryEngine queryEngine = (MongoDBQueryEngine) dao.getQueryEngine();
+        queryEngine.setConf(configuration);
+        final CloseableIterable<RyaStatement> iter = queryEngine.query(new RyaQuery(statement));
+
+        // Check if user has authorization to view document based on its visibility
+        final boolean hasNext = iter.iterator().hasNext();
+
+        // Reset
+        dao.delete(statement, configuration);
+        assertEquals(coll.count(), 0);
+        dao.getConf().setAuths(AuthorizationsUtil.getAuthorizationsStringArray(Authorizations.EMPTY));
+
+        return hasNext;
+    }
+
+    private static RyaStatement buildVisibilityTestRyaStatement(final String documentVisibility) {
+        final RyaStatementBuilder builder = new RyaStatementBuilder();
+        builder.setPredicate(new RyaURI("http://temp.com"));
+        builder.setSubject(new RyaURI("http://subject.com"));
+        builder.setObject(new RyaURI("http://object.com"));
+        builder.setContext(new RyaURI("http://context.com"));
+        builder.setColumnVisibility(documentVisibility != null ? documentVisibility.getBytes() : null);
+        final RyaStatement statement = builder.build();
+        return statement;
+    }
 }