This is an automated email from the ASF dual-hosted git repository.

kturner pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/accumulo.git


The following commit(s) were added to refs/heads/main by this push:
     new 1e347f8482 updates column visibility to use accumulo access library 
(#3746)
1e347f8482 is described below

commit 1e347f84828a597d97f698e276be11c12d37f41d
Author: Keith Turner <ktur...@apache.org>
AuthorDate: Mon Jul 8 14:38:36 2024 -0700

    updates column visibility to use accumulo access library (#3746)
    
    Updates ColumnVisibility and VisibilityEvaluator to use the Accumulo Access 
control library :
    
    https://github.com/apache/accumulo-access
    
    
    Co-authored-by: Dave Marion <dlmar...@apache.org>
---
 assemble/pom.xml                                   |   5 +
 core/pom.xml                                       |   6 +
 .../summarizers/AuthorizationSummarizer.java       |  36 +-----
 .../core/clientImpl/ConditionalWriterImpl.java     |  29 ++---
 .../data/constraints/VisibilityConstraint.java     |  16 +--
 .../core/iterators/user/TransformingIterator.java  |  23 ++--
 .../core/iterators/user/VisibilityFilter.java      |  20 +--
 .../iteratorsImpl/system/VisibilityFilter.java     |  19 ++-
 .../accumulo/core/security/Authorizations.java     |  20 +++
 .../accumulo/core/security/ColumnVisibility.java   |  85 ++++++++-----
 .../core/security/VisibilityEvaluator.java         | 134 +++------------------
 .../core/security/VisibilityParseException.java    |  11 ++
 .../accumulo/core/util/BadArgumentException.java   |   7 ++
 .../data/constraints/VisibilityConstraintTest.java |  13 +-
 .../core/security/ColumnVisibilityTest.java        |  13 ++
 .../core/security/VisibilityEvaluatorTest.java     |  24 +---
 pom.xml                                            |   6 +
 17 files changed, 206 insertions(+), 261 deletions(-)

diff --git a/assemble/pom.xml b/assemble/pom.xml
index 4e0bc83497..fbb5a9e698 100644
--- a/assemble/pom.xml
+++ b/assemble/pom.xml
@@ -181,6 +181,11 @@
       <artifactId>jakarta.xml.bind-api</artifactId>
       <optional>true</optional>
     </dependency>
+    <dependency>
+      <groupId>org.apache.accumulo</groupId>
+      <artifactId>accumulo-access</artifactId>
+      <optional>true</optional>
+    </dependency>
     <dependency>
       <groupId>org.apache.accumulo</groupId>
       <artifactId>accumulo-compaction-coordinator</artifactId>
diff --git a/core/pom.xml b/core/pom.xml
index c064563a4e..ff2523748f 100644
--- a/core/pom.xml
+++ b/core/pom.xml
@@ -81,6 +81,10 @@
       <groupId>io.opentelemetry</groupId>
       <artifactId>opentelemetry-context</artifactId>
     </dependency>
+    <dependency>
+      <groupId>org.apache.accumulo</groupId>
+      <artifactId>accumulo-access</artifactId>
+    </dependency>
     <dependency>
       <groupId>org.apache.accumulo</groupId>
       <artifactId>accumulo-start</artifactId>
@@ -272,6 +276,8 @@
                 <allow>javax[.]security[.]auth[.]DestroyFailedException</allow>
                 <!-- allow questionable Hadoop exceptions for mapreduce -->
                 
<allow>org[.]apache[.]hadoop[.]mapred[.](FileAlreadyExistsException|InvalidJobConfException)</allow>
+                <!-- allow the following types from the visibility API -->
+                <allow>org[.]apache[.]accumulo[.]access[.].*</allow>
               </allows>
             </configuration>
           </execution>
diff --git 
a/core/src/main/java/org/apache/accumulo/core/client/summary/summarizers/AuthorizationSummarizer.java
 
b/core/src/main/java/org/apache/accumulo/core/client/summary/summarizers/AuthorizationSummarizer.java
index 5660f665c3..77a92442e5 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/client/summary/summarizers/AuthorizationSummarizer.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/client/summary/summarizers/AuthorizationSummarizer.java
@@ -24,14 +24,13 @@ import java.util.Map;
 import java.util.Set;
 import java.util.function.Consumer;
 
+import org.apache.accumulo.access.AccessExpression;
 import org.apache.accumulo.core.client.admin.TableOperations;
 import org.apache.accumulo.core.client.summary.CountingSummarizer;
 import org.apache.accumulo.core.data.ArrayByteSequence;
 import org.apache.accumulo.core.data.ByteSequence;
 import org.apache.accumulo.core.data.Key;
 import org.apache.accumulo.core.data.Value;
-import org.apache.accumulo.core.security.ColumnVisibility;
-import org.apache.accumulo.core.security.ColumnVisibility.Node;
 
 /**
  * Counts unique authorizations in column visibility labels. Leverages super 
class to defend against
@@ -82,7 +81,10 @@ public class AuthorizationSummarizer extends 
CountingSummarizer<ByteSequence> {
       if (vis.length() > 0) {
         Set<ByteSequence> auths = cache.get(vis);
         if (auths == null) {
-          auths = findAuths(vis);
+          auths = new HashSet<>();
+          for (String auth : 
AccessExpression.of(vis.toArray()).getAuthorizations().asSet()) {
+            auths.add(new ArrayByteSequence(auth));
+          }
           cache.put(new ArrayByteSequence(vis), auths);
         }
 
@@ -91,33 +93,5 @@ public class AuthorizationSummarizer extends 
CountingSummarizer<ByteSequence> {
         }
       }
     }
-
-    private Set<ByteSequence> findAuths(ByteSequence vis) {
-      HashSet<ByteSequence> auths = new HashSet<>();
-      byte[] expression = vis.toArray();
-      Node root = new ColumnVisibility(expression).getParseTree();
-
-      findAuths(root, expression, auths);
-
-      return auths;
-    }
-
-    private void findAuths(Node node, byte[] expression, HashSet<ByteSequence> 
auths) {
-      switch (node.getType()) {
-        case AND:
-        case OR:
-          for (Node child : node.getChildren()) {
-            findAuths(child, expression, auths);
-          }
-          break;
-        case TERM:
-          auths.add(node.getTerm(expression));
-          break;
-        case EMPTY:
-          break;
-        default:
-          throw new IllegalArgumentException("Unknown node type " + 
node.getType());
-      }
-    }
   }
 }
diff --git 
a/core/src/main/java/org/apache/accumulo/core/clientImpl/ConditionalWriterImpl.java
 
b/core/src/main/java/org/apache/accumulo/core/clientImpl/ConditionalWriterImpl.java
index 3137a19f00..4ddcdae552 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/clientImpl/ConditionalWriterImpl.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/clientImpl/ConditionalWriterImpl.java
@@ -42,6 +42,8 @@ import java.util.concurrent.ScheduledFuture;
 import java.util.concurrent.ScheduledThreadPoolExecutor;
 import java.util.concurrent.TimeUnit;
 
+import org.apache.accumulo.access.AccessEvaluator;
+import org.apache.accumulo.access.IllegalAccessExpressionException;
 import org.apache.accumulo.core.Constants;
 import org.apache.accumulo.core.client.AccumuloException;
 import org.apache.accumulo.core.client.AccumuloSecurityException;
@@ -69,13 +71,9 @@ import org.apache.accumulo.core.lock.ServiceLock;
 import org.apache.accumulo.core.rpc.ThriftUtil;
 import org.apache.accumulo.core.rpc.clients.ThriftClientTypes;
 import org.apache.accumulo.core.security.Authorizations;
-import org.apache.accumulo.core.security.ColumnVisibility;
-import org.apache.accumulo.core.security.VisibilityEvaluator;
-import org.apache.accumulo.core.security.VisibilityParseException;
 import org.apache.accumulo.core.tabletingest.thrift.TabletIngestClientService;
 import org.apache.accumulo.core.tabletserver.thrift.NoSuchScanIDException;
 import org.apache.accumulo.core.trace.TraceUtil;
-import org.apache.accumulo.core.util.BadArgumentException;
 import org.apache.accumulo.core.util.ByteBufferUtil;
 import org.apache.accumulo.core.util.threads.ThreadPools;
 import org.apache.accumulo.core.util.threads.Threads;
@@ -97,14 +95,14 @@ class ConditionalWriterImpl implements ConditionalWriter {
 
   private static final int MAX_SLEEP = 30000;
 
-  private Authorizations auths;
-  private VisibilityEvaluator ve;
-  private Map<Text,Boolean> cache = Collections.synchronizedMap(new 
LRUMap<>(1000));
+  private final Authorizations auths;
+  private final AccessEvaluator accessEvaluator;
+  private final Map<Text,Boolean> cache = Collections.synchronizedMap(new 
LRUMap<>(1000));
   private final ClientContext context;
-  private TabletLocator locator;
+  private final TabletLocator locator;
   private final TableId tableId;
   private final String tableName;
-  private long timeout;
+  private final long timeout;
   private final Durability durability;
   private final String classLoaderContext;
 
@@ -374,7 +372,7 @@ class ConditionalWriterImpl implements ConditionalWriter {
       ConditionalWriterConfig config) {
     this.context = context;
     this.auths = config.getAuthorizations();
-    this.ve = new VisibilityEvaluator(config.getAuthorizations());
+    this.accessEvaluator = 
AccessEvaluator.of(config.getAuthorizations().toAccessAuthorizations());
     this.threadPool = context.threadPools().createScheduledExecutorService(
         config.getMaxWriteThreads(), this.getClass().getSimpleName());
     this.locator = new SyncingTabletLocator(context, tableId);
@@ -808,21 +806,24 @@ class ConditionalWriterImpl implements ConditionalWriter {
   }
 
   private boolean isVisible(ByteSequence cv) {
-    Text testVis = new Text(cv.toArray());
-    if (testVis.getLength() == 0) {
+
+    if (cv.length() == 0) {
       return true;
     }
 
+    byte[] arrayVis = cv.toArray();
+    Text testVis = new Text(arrayVis);
+
     Boolean b = cache.get(testVis);
     if (b != null) {
       return b;
     }
 
     try {
-      boolean bb = ve.evaluate(new ColumnVisibility(testVis));
+      boolean bb = accessEvaluator.canAccess(arrayVis);
       cache.put(new Text(testVis), bb);
       return bb;
-    } catch (VisibilityParseException | BadArgumentException e) {
+    } catch (IllegalAccessExpressionException e) {
       return false;
     }
   }
diff --git 
a/core/src/main/java/org/apache/accumulo/core/data/constraints/VisibilityConstraint.java
 
b/core/src/main/java/org/apache/accumulo/core/data/constraints/VisibilityConstraint.java
index 62531c5fa0..26f55f109a 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/data/constraints/VisibilityConstraint.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/data/constraints/VisibilityConstraint.java
@@ -24,12 +24,11 @@ import java.util.Collections;
 import java.util.HashSet;
 import java.util.List;
 
+import org.apache.accumulo.access.AccessEvaluator;
+import org.apache.accumulo.access.IllegalAccessExpressionException;
+import org.apache.accumulo.core.data.ArrayByteSequence;
 import org.apache.accumulo.core.data.ColumnUpdate;
 import org.apache.accumulo.core.data.Mutation;
-import org.apache.accumulo.core.security.ColumnVisibility;
-import org.apache.accumulo.core.security.VisibilityEvaluator;
-import org.apache.accumulo.core.security.VisibilityParseException;
-import org.apache.accumulo.core.util.BadArgumentException;
 
 /**
  * A constraint that checks the visibility of columns against the actor's 
authorizations. Violation
@@ -64,7 +63,7 @@ public class VisibilityConstraint implements Constraint {
       ok = new HashSet<>();
     }
 
-    VisibilityEvaluator ve = null;
+    AccessEvaluator ve = null;
 
     for (ColumnUpdate update : updates) {
 
@@ -78,14 +77,15 @@ public class VisibilityConstraint implements Constraint {
         try {
 
           if (ve == null) {
-            ve = new VisibilityEvaluator(env.getAuthorizationsContainer());
+            var authContainer = env.getAuthorizationsContainer();
+            ve = AccessEvaluator.of(auth -> authContainer.contains(new 
ArrayByteSequence(auth)));
           }
 
-          if (!ve.evaluate(new ColumnVisibility(cv))) {
+          if (!ve.canAccess(cv)) {
             return Collections.singletonList((short) 2);
           }
 
-        } catch (BadArgumentException | VisibilityParseException bae) {
+        } catch (IllegalAccessExpressionException iaee) {
           return Collections.singletonList((short) 1);
         }
 
diff --git 
a/core/src/main/java/org/apache/accumulo/core/iterators/user/TransformingIterator.java
 
b/core/src/main/java/org/apache/accumulo/core/iterators/user/TransformingIterator.java
index be8d63330e..10dffb0083 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/iterators/user/TransformingIterator.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/iterators/user/TransformingIterator.java
@@ -30,6 +30,9 @@ import java.util.Map;
 import java.util.Map.Entry;
 import java.util.NoSuchElementException;
 
+import org.apache.accumulo.access.AccessEvaluator;
+import org.apache.accumulo.access.AccessExpression;
+import org.apache.accumulo.access.IllegalAccessExpressionException;
 import org.apache.accumulo.core.client.IteratorSetting;
 import org.apache.accumulo.core.conf.ConfigurationTypeHelper;
 import org.apache.accumulo.core.data.ByteSequence;
@@ -43,10 +46,6 @@ import org.apache.accumulo.core.iterators.OptionDescriber;
 import org.apache.accumulo.core.iterators.SortedKeyValueIterator;
 import org.apache.accumulo.core.iterators.WrappingIterator;
 import org.apache.accumulo.core.security.Authorizations;
-import org.apache.accumulo.core.security.ColumnVisibility;
-import org.apache.accumulo.core.security.VisibilityEvaluator;
-import org.apache.accumulo.core.security.VisibilityParseException;
-import org.apache.accumulo.core.util.BadArgumentException;
 import org.apache.accumulo.core.util.Pair;
 import org.apache.commons.collections4.map.LRUMap;
 import org.apache.hadoop.io.Text;
@@ -103,7 +102,7 @@ public abstract class TransformingIterator extends 
WrappingIterator implements O
   protected Collection<ByteSequence> seekColumnFamilies;
   protected boolean seekColumnFamiliesInclusive;
 
-  private VisibilityEvaluator ve = null;
+  private AccessEvaluator ve = null;
   private LRUMap<ByteSequence,Boolean> visibleCache = null;
   private LRUMap<ByteSequence,Boolean> parsedVisibilitiesCache = null;
   private long maxBufferSize;
@@ -118,7 +117,7 @@ public abstract class TransformingIterator extends 
WrappingIterator implements O
     if (scanning) {
       String auths = options.get(AUTH_OPT);
       if (auths != null && !auths.isEmpty()) {
-        ve = new VisibilityEvaluator(new 
Authorizations(auths.getBytes(UTF_8)));
+        ve = AccessEvaluator.of(new 
Authorizations(auths.getBytes(UTF_8)).toAccessAuthorizations());
         visibleCache = new LRUMap<>(100);
       }
     }
@@ -409,13 +408,12 @@ public abstract class TransformingIterator extends 
WrappingIterator implements O
     // Ensure that the visibility (which could have been transformed) parses. 
Must always do this
     // check, even if visibility is not evaluated.
     ByteSequence visibility = key.getColumnVisibilityData();
-    ColumnVisibility colVis = null;
     Boolean parsed = parsedVisibilitiesCache.get(visibility);
     if (parsed == null) {
       try {
-        colVis = new ColumnVisibility(visibility.toArray());
+        AccessExpression.validate(visibility.toArray());
         parsedVisibilitiesCache.put(visibility, Boolean.TRUE);
-      } catch (BadArgumentException e) {
+      } catch (IllegalAccessExpressionException e) {
         log.error("Parse error after transformation : {}", visibility);
         parsedVisibilitiesCache.put(visibility, Boolean.FALSE);
         if (scanning) {
@@ -441,12 +439,9 @@ public abstract class TransformingIterator extends 
WrappingIterator implements O
     visible = visibleCache.get(visibility);
     if (visible == null) {
       try {
-        if (colVis == null) {
-          colVis = new ColumnVisibility(visibility.toArray());
-        }
-        visible = ve.evaluate(colVis);
+        visible = ve.canAccess(visibility.toArray());
         visibleCache.put(visibility, visible);
-      } catch (VisibilityParseException | BadArgumentException e) {
+      } catch (IllegalAccessExpressionException e) {
         log.error("Parse Error", e);
         visible = Boolean.FALSE;
       }
diff --git 
a/core/src/main/java/org/apache/accumulo/core/iterators/user/VisibilityFilter.java
 
b/core/src/main/java/org/apache/accumulo/core/iterators/user/VisibilityFilter.java
index c91009bb6f..92fb75a72d 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/iterators/user/VisibilityFilter.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/iterators/user/VisibilityFilter.java
@@ -23,6 +23,9 @@ import static java.nio.charset.StandardCharsets.UTF_8;
 import java.io.IOException;
 import java.util.Map;
 
+import org.apache.accumulo.access.AccessEvaluator;
+import org.apache.accumulo.access.AccessExpression;
+import org.apache.accumulo.access.IllegalAccessExpressionException;
 import org.apache.accumulo.core.client.IteratorSetting;
 import org.apache.accumulo.core.data.ByteSequence;
 import org.apache.accumulo.core.data.Key;
@@ -32,10 +35,6 @@ import 
org.apache.accumulo.core.iterators.IteratorEnvironment;
 import org.apache.accumulo.core.iterators.OptionDescriber;
 import org.apache.accumulo.core.iterators.SortedKeyValueIterator;
 import org.apache.accumulo.core.security.Authorizations;
-import org.apache.accumulo.core.security.ColumnVisibility;
-import org.apache.accumulo.core.security.VisibilityEvaluator;
-import org.apache.accumulo.core.security.VisibilityParseException;
-import org.apache.accumulo.core.util.BadArgumentException;
 import org.apache.commons.collections4.map.LRUMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -45,7 +44,7 @@ import org.slf4j.LoggerFactory;
  */
 public class VisibilityFilter extends Filter implements OptionDescriber {
 
-  protected VisibilityEvaluator ve;
+  private AccessEvaluator accessEvaluator;
   protected Map<ByteSequence,Boolean> cache;
 
   private static final Logger log = 
LoggerFactory.getLogger(VisibilityFilter.class);
@@ -66,7 +65,8 @@ public class VisibilityFilter extends Filter implements 
OptionDescriber {
       String auths = options.get(AUTHS);
       Authorizations authObj = auths == null || auths.isEmpty() ? new 
Authorizations()
           : new Authorizations(auths.getBytes(UTF_8));
-      this.ve = new VisibilityEvaluator(authObj);
+
+      this.accessEvaluator = 
AccessEvaluator.of(authObj.toAccessAuthorizations());
     }
     this.cache = new LRUMap<>(1000);
   }
@@ -80,10 +80,10 @@ public class VisibilityFilter extends Filter implements 
OptionDescriber {
         return b;
       }
       try {
-        new ColumnVisibility(testVis.toArray());
+        AccessExpression.validate(testVis.toArray());
         cache.put(testVis, true);
         return true;
-      } catch (BadArgumentException e) {
+      } catch (IllegalAccessExpressionException e) {
         cache.put(testVis, false);
         return false;
       }
@@ -98,10 +98,10 @@ public class VisibilityFilter extends Filter implements 
OptionDescriber {
       }
 
       try {
-        boolean bb = ve.evaluate(new ColumnVisibility(testVis.toArray()));
+        boolean bb = accessEvaluator.canAccess(testVis.toArray());
         cache.put(testVis, bb);
         return bb;
-      } catch (VisibilityParseException | BadArgumentException e) {
+      } catch (IllegalAccessExpressionException e) {
         log.error("Parse Error", e);
         return false;
       }
diff --git 
a/core/src/main/java/org/apache/accumulo/core/iteratorsImpl/system/VisibilityFilter.java
 
b/core/src/main/java/org/apache/accumulo/core/iteratorsImpl/system/VisibilityFilter.java
index 0a0fd5f4aa..22acd782ea 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/iteratorsImpl/system/VisibilityFilter.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/iteratorsImpl/system/VisibilityFilter.java
@@ -18,6 +18,8 @@
  */
 package org.apache.accumulo.core.iteratorsImpl.system;
 
+import org.apache.accumulo.access.AccessEvaluator;
+import org.apache.accumulo.access.IllegalAccessExpressionException;
 import org.apache.accumulo.core.data.ArrayByteSequence;
 import org.apache.accumulo.core.data.ByteSequence;
 import org.apache.accumulo.core.data.Key;
@@ -26,10 +28,6 @@ import 
org.apache.accumulo.core.iterators.IteratorEnvironment;
 import org.apache.accumulo.core.iterators.SortedKeyValueIterator;
 import org.apache.accumulo.core.iterators.SynchronizedServerFilter;
 import org.apache.accumulo.core.security.Authorizations;
-import org.apache.accumulo.core.security.ColumnVisibility;
-import org.apache.accumulo.core.security.VisibilityEvaluator;
-import org.apache.accumulo.core.security.VisibilityParseException;
-import org.apache.accumulo.core.util.BadArgumentException;
 import org.apache.commons.collections4.map.LRUMap;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -43,7 +41,7 @@ import org.slf4j.LoggerFactory;
  * class.
  */
 public class VisibilityFilter extends SynchronizedServerFilter {
-  protected VisibilityEvaluator ve;
+  protected AccessEvaluator ve;
   protected ByteSequence defaultVisibility;
   protected LRUMap<ByteSequence,Boolean> cache;
   protected Authorizations authorizations;
@@ -53,7 +51,7 @@ public class VisibilityFilter extends 
SynchronizedServerFilter {
   private VisibilityFilter(SortedKeyValueIterator<Key,Value> iterator,
       Authorizations authorizations, byte[] defaultVisibility) {
     super(iterator);
-    this.ve = new VisibilityEvaluator(authorizations);
+    this.ve = AccessEvaluator.of(authorizations.toAccessAuthorizations());
     this.authorizations = authorizations;
     this.defaultVisibility = new ArrayByteSequence(defaultVisibility);
     this.cache = new LRUMap<>(1000);
@@ -80,14 +78,11 @@ public class VisibilityFilter extends 
SynchronizedServerFilter {
     }
 
     try {
-      boolean bb = ve.evaluate(new ColumnVisibility(testVis.toArray()));
+      boolean bb = ve.canAccess(testVis.toArray());
       cache.put(testVis, bb);
       return bb;
-    } catch (VisibilityParseException e) {
-      log.error("VisibilityParseException with visibility of Key: {}", k, e);
-      return false;
-    } catch (BadArgumentException e) {
-      log.error("BadArgumentException with visibility of Key: {}", k, e);
+    } catch (IllegalAccessExpressionException e) {
+      log.error("IllegalAccessExpressionException with visibility of Key: {}", 
k, e);
       return false;
     }
   }
diff --git 
a/core/src/main/java/org/apache/accumulo/core/security/Authorizations.java 
b/core/src/main/java/org/apache/accumulo/core/security/Authorizations.java
index 1cfeebb8b9..363a0586f8 100644
--- a/core/src/main/java/org/apache/accumulo/core/security/Authorizations.java
+++ b/core/src/main/java/org/apache/accumulo/core/security/Authorizations.java
@@ -385,4 +385,24 @@ public class Authorizations implements Iterable<byte[]>, 
Serializable, Authoriza
 
     return sb.toString();
   }
+
+  private static final org.apache.accumulo.access.Authorizations 
EMPTY_ACCESS_AUTH =
+      org.apache.accumulo.access.Authorizations.of(Set.of());
+
+  /**
+   * Converts to an Accumulo Access Authorizations object.
+   *
+   * @since 3.1.0
+   */
+  public org.apache.accumulo.access.Authorizations toAccessAuthorizations() {
+    if (auths.isEmpty()) {
+      return EMPTY_ACCESS_AUTH;
+    } else {
+      Set<String> auths = new HashSet<>(authsList.size());
+      for (var auth : authsList) {
+        auths.add(new String(auth, UTF_8));
+      }
+      return org.apache.accumulo.access.Authorizations.of(auths);
+    }
+  }
 }
diff --git 
a/core/src/main/java/org/apache/accumulo/core/security/ColumnVisibility.java 
b/core/src/main/java/org/apache/accumulo/core/security/ColumnVisibility.java
index 4b8784be02..338cf1396c 100644
--- a/core/src/main/java/org/apache/accumulo/core/security/ColumnVisibility.java
+++ b/core/src/main/java/org/apache/accumulo/core/security/ColumnVisibility.java
@@ -27,7 +27,10 @@ import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
 import java.util.TreeSet;
+import java.util.function.Supplier;
 
+import org.apache.accumulo.access.AccessExpression;
+import org.apache.accumulo.access.IllegalAccessExpressionException;
 import org.apache.accumulo.core.data.ArrayByteSequence;
 import org.apache.accumulo.core.data.ByteSequence;
 import org.apache.accumulo.core.util.BadArgumentException;
@@ -35,6 +38,8 @@ import org.apache.accumulo.core.util.TextUtil;
 import org.apache.hadoop.io.Text;
 import org.apache.hadoop.io.WritableComparator;
 
+import com.google.common.base.Suppliers;
+
 /**
  * Validate the column visibility is a valid expression and set the visibility 
for a Mutation. See
  * {@link ColumnVisibility#ColumnVisibility(byte[])} for the definition of an 
expression.
@@ -76,8 +81,10 @@ import org.apache.hadoop.io.WritableComparator;
  */
 public class ColumnVisibility {
 
-  Node node = null;
-  private byte[] expression;
+  // This functionality is deprecated so its setup as a supplier so it is only 
computed if the
+  // deprecated functionality is called.
+  private final Supplier<Node> nodeSupplier;
+  private final byte[] expression;
 
   /**
    * Accessor for the underlying byte string.
@@ -91,6 +98,7 @@ public class ColumnVisibility {
   /**
    * The node types in a parse tree for a visibility expression.
    */
+  @Deprecated(since = "3.1.0")
   public enum NodeType {
     EMPTY, TERM, OR, AND,
   }
@@ -103,6 +111,7 @@ public class ColumnVisibility {
   /**
    * A node in the parse tree for a visibility expression.
    */
+  @Deprecated(since = "3.1.0")
   public static class Node {
     /**
      * An empty list of nodes.
@@ -169,6 +178,7 @@ public class ColumnVisibility {
    * A node comparator. Nodes sort according to node type, terms sort 
lexicographically. AND and OR
    * nodes sort by number of children, or if the same by corresponding 
children.
    */
+  @Deprecated(since = "3.1.0")
   public static class NodeComparator implements Comparator<Node>, Serializable 
{
 
     private static final long serialVersionUID = 1L;
@@ -216,6 +226,7 @@ public class ColumnVisibility {
    * Convenience method that delegates to normalize with a new NodeComparator 
constructed using the
    * supplied expression.
    */
+  @Deprecated(since = "3.1.0")
   public static Node normalize(Node root, byte[] expression) {
     return normalize(root, expression, new NodeComparator(expression));
   }
@@ -228,6 +239,7 @@ public class ColumnVisibility {
    *  3) dedupes labels (`a&b&a` becomes `a&b`)
    */
   // @formatter:on
+  @Deprecated(since = "3.1.0")
   public static Node normalize(Node root, byte[] expression, NodeComparator 
comparator) {
     if (root.type != NodeType.TERM) {
       TreeSet<Node> rolledUp = new TreeSet<>(comparator);
@@ -256,6 +268,7 @@ public class ColumnVisibility {
    * Walks an expression's AST and appends a string representation to a 
supplied StringBuilder. This
    * method adds parens where necessary.
    */
+  @Deprecated(since = "3.1.0")
   public static void stringify(Node root, byte[] expression, StringBuilder 
out) {
     if (root.type == NodeType.TERM) {
       out.append(new String(expression, root.start, root.end - root.start, 
UTF_8));
@@ -282,13 +295,12 @@ public class ColumnVisibility {
    *
    * @return normalized expression in byte[] form
    */
+  @Deprecated(since = "3.1.0")
   public byte[] flatten() {
-    Node normRoot = normalize(node, expression);
-    StringBuilder builder = new StringBuilder(expression.length);
-    stringify(normRoot, expression, builder);
-    return builder.toString().getBytes(UTF_8);
+    return AccessExpression.of(expression, 
true).getExpression().getBytes(UTF_8);
   }
 
+  @Deprecated
   private static class ColumnVisibilityParser {
     private int index = 0;
     private int parens = 0;
@@ -455,16 +467,17 @@ public class ColumnVisibility {
     }
   }
 
-  private void validate(byte[] expression) {
+  private Node createNodeTree(byte[] expression) {
     if (expression != null && expression.length > 0) {
       ColumnVisibilityParser p = new ColumnVisibilityParser();
-      node = p.parse(expression);
+      return p.parse(expression);
     } else {
-      node = EMPTY_NODE;
+      return EMPTY_NODE;
     }
-    this.expression = expression;
   }
 
+  private static final byte[] EMPTY_BYTES = new byte[0];
+
   /**
    * Creates an empty visibility. Normally, elements with empty visibility can 
be seen by everyone.
    * Though, one could change this behavior with filters.
@@ -472,7 +485,8 @@ public class ColumnVisibility {
    * @see #ColumnVisibility(String)
    */
   public ColumnVisibility() {
-    this(new byte[] {});
+    expression = EMPTY_BYTES;
+    nodeSupplier = Suppliers.memoize(() -> createNodeTree(expression));
   }
 
   /**
@@ -496,13 +510,34 @@ public class ColumnVisibility {
   }
 
   /**
-   * Creates a column visibility for a Mutation from a string already encoded 
in UTF-8 bytes.
+   * Creates a column visibility for a Mutation from bytes already encoded in 
UTF-8.
    *
    * @param expression visibility expression, encoded as UTF-8 bytes
    * @see #ColumnVisibility(String)
    */
   public ColumnVisibility(byte[] expression) {
-    validate(expression);
+    this.expression = expression;
+    try {
+      AccessExpression.validate(this.expression);
+    } catch (IllegalAccessExpressionException e) {
+      // This is thrown for compatability with the exception this class used 
to throw when it parsed
+      // exceptions itself.
+      throw new BadArgumentException(e);
+    }
+    nodeSupplier = Suppliers.memoize(() -> createNodeTree(this.expression));
+  }
+
+  /**
+   * Creates a column visibility for a Mutation from an AccessExpression.
+   *
+   * @param expression visibility expression, encoded as UTF-8 bytes
+   * @see #ColumnVisibility(String)
+   * @since 3.1.0
+   */
+  public ColumnVisibility(AccessExpression expression) {
+    // AccessExpression is a validated immutable object, so no need to re 
validate
+    this.expression = expression.getExpression().getBytes(UTF_8);
+    nodeSupplier = Suppliers.memoize(() -> createNodeTree(this.expression));
   }
 
   @Override
@@ -542,8 +577,9 @@ public class ColumnVisibility {
    *
    * @return parse tree node
    */
+  @Deprecated(since = "3.1.0")
   public Node getParseTree() {
-    return node;
+    return nodeSupplier.get();
   }
 
   /**
@@ -564,9 +600,11 @@ public class ColumnVisibility {
    *
    * @param term term to quote
    * @return quoted term (unquoted if unnecessary)
+   * @deprecated use {@link AccessExpression#quote(String)}
    */
+  @Deprecated(since = "3.1.0")
   public static String quote(String term) {
-    return new String(quote(term.getBytes(UTF_8)), UTF_8);
+    return AccessExpression.quote(term);
   }
 
   /**
@@ -576,21 +614,10 @@ public class ColumnVisibility {
    * @param term term to quote, encoded as UTF-8 bytes
    * @return quoted term (unquoted if unnecessary), encoded as UTF-8 bytes
    * @see #quote(String)
+   * @deprecated use {@link AccessExpression#quote(byte[])}
    */
+  @Deprecated(since = "3.1.0")
   public static byte[] quote(byte[] term) {
-    boolean needsQuote = false;
-
-    for (byte b : term) {
-      if (!Authorizations.isValidAuthChar(b)) {
-        needsQuote = true;
-        break;
-      }
-    }
-
-    if (!needsQuote) {
-      return term;
-    }
-
-    return VisibilityEvaluator.escape(term, true);
+    return AccessExpression.quote(term);
   }
 }
diff --git 
a/core/src/main/java/org/apache/accumulo/core/security/VisibilityEvaluator.java 
b/core/src/main/java/org/apache/accumulo/core/security/VisibilityEvaluator.java
index dd07d64086..aa5d85f530 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/security/VisibilityEvaluator.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/security/VisibilityEvaluator.java
@@ -18,92 +18,18 @@
  */
 package org.apache.accumulo.core.security;
 
-import java.util.ArrayList;
-
+import org.apache.accumulo.access.AccessEvaluator;
+import org.apache.accumulo.access.IllegalAccessExpressionException;
 import org.apache.accumulo.core.data.ArrayByteSequence;
-import org.apache.accumulo.core.data.ByteSequence;
-import org.apache.accumulo.core.security.ColumnVisibility.Node;
 
 /**
  * A class which evaluates visibility expressions against a set of 
authorizations.
+ *
+ * @deprecated since 3.1.0 Use Accumulo Access library instead
  */
+@Deprecated(since = "3.1.0")
 public class VisibilityEvaluator {
-  private AuthorizationContainer auths;
-
-  /**
-   * Authorizations in column visibility expression are in escaped form. 
Column visibility parsing
-   * does not unescape. This class wraps an AuthorizationContainer and 
unescapes auths before
-   * checking the wrapped container.
-   */
-  private static class UnescapingAuthorizationContainer implements 
AuthorizationContainer {
-
-    private AuthorizationContainer wrapped;
-
-    UnescapingAuthorizationContainer(AuthorizationContainer wrapee) {
-      this.wrapped = wrapee;
-    }
-
-    @Override
-    public boolean contains(ByteSequence auth) {
-      return wrapped.contains(unescape(auth));
-    }
-  }
-
-  static ByteSequence unescape(ByteSequence auth) {
-    int escapeCharCount = 0;
-    for (int i = 0; i < auth.length(); i++) {
-      byte b = auth.byteAt(i);
-      if (b == '"' || b == '\\') {
-        escapeCharCount++;
-      }
-    }
-
-    if (escapeCharCount > 0) {
-      if (escapeCharCount % 2 == 1) {
-        throw new IllegalArgumentException("Illegal escape sequence in auth : 
" + auth);
-      }
-
-      byte[] unescapedCopy = new byte[auth.length() - escapeCharCount / 2];
-      int pos = 0;
-      for (int i = 0; i < auth.length(); i++) {
-        byte b = auth.byteAt(i);
-        if (b == '\\') {
-          i++;
-          b = auth.byteAt(i);
-          if (b != '"' && b != '\\') {
-            throw new IllegalArgumentException("Illegal escape sequence in 
auth : " + auth);
-          }
-        } else if (b == '"') {
-          // should only see quote after a slash
-          throw new IllegalArgumentException("Illegal escape sequence in auth 
: " + auth);
-        }
-
-        unescapedCopy[pos++] = b;
-      }
-
-      return new ArrayByteSequence(unescapedCopy);
-    } else {
-      return auth;
-    }
-  }
-
-  /**
-   * Creates a new {@link Authorizations} object with escaped forms of the 
authorizations in the
-   * given object.
-   *
-   * @param auths original authorizations
-   * @return authorizations object with escaped authorization strings
-   * @see #escape(byte[], boolean)
-   */
-  static Authorizations escape(Authorizations auths) {
-    ArrayList<byte[]> retAuths = new 
ArrayList<>(auths.getAuthorizations().size());
-
-    for (byte[] auth : auths.getAuthorizations()) {
-      retAuths.add(escape(auth, false));
-    }
-
-    return new Authorizations(retAuths);
-  }
+  private final AccessEvaluator accessEvaluator;
 
   /**
    * Properly escapes an authorization string. The string can be quoted if 
desired.
@@ -147,7 +73,9 @@ public class VisibilityEvaluator {
    * @since 1.7.0
    */
   public VisibilityEvaluator(AuthorizationContainer authsContainer) {
-    this.auths = new UnescapingAuthorizationContainer(authsContainer);
+    // TODO need to look into efficiency and correctness of this
+    this.accessEvaluator =
+        AccessEvaluator.of(auth -> authsContainer.contains(new 
ArrayByteSequence(auth)));
   }
 
   /**
@@ -157,7 +85,7 @@ public class VisibilityEvaluator {
    * @param authorizations authorizations object
    */
   public VisibilityEvaluator(Authorizations authorizations) {
-    this.auths = escape(authorizations);
+    this.accessEvaluator = 
AccessEvaluator.of(authorizations.toAccessAuthorizations());
   }
 
   /**
@@ -171,42 +99,12 @@ public class VisibilityEvaluator {
    *         subexpression is of an unknown type
    */
   public boolean evaluate(ColumnVisibility visibility) throws 
VisibilityParseException {
-    // The VisibilityEvaluator computes a trie from the given Authorizations, 
that ColumnVisibility
-    // expressions can be evaluated against.
-    return evaluate(visibility.getExpression(), visibility.getParseTree());
-  }
-
-  private final boolean evaluate(final byte[] expression, final Node root)
-      throws VisibilityParseException {
-    if (expression.length == 0) {
-      return true;
-    }
-    switch (root.type) {
-      case TERM:
-        return auths.contains(root.getTerm(expression));
-      case AND:
-        if (root.children == null || root.children.size() < 2) {
-          throw new VisibilityParseException("AND has less than 2 children", 
expression,
-              root.start);
-        }
-        for (Node child : root.children) {
-          if (!evaluate(expression, child)) {
-            return false;
-          }
-        }
-        return true;
-      case OR:
-        if (root.children == null || root.children.size() < 2) {
-          throw new VisibilityParseException("OR has less than 2 children", 
expression, root.start);
-        }
-        for (Node child : root.children) {
-          if (evaluate(expression, child)) {
-            return true;
-          }
-        }
-        return false;
-      default:
-        throw new VisibilityParseException("No such node type", expression, 
root.start);
+    try {
+      return accessEvaluator.canAccess(visibility.getExpression());
+    } catch (IllegalAccessExpressionException e) {
+      // This is thrown for compatability with the exception this class used 
to evaluate expressions
+      // itself.
+      throw new VisibilityParseException(e);
     }
   }
 }
diff --git 
a/core/src/main/java/org/apache/accumulo/core/security/VisibilityParseException.java
 
b/core/src/main/java/org/apache/accumulo/core/security/VisibilityParseException.java
index 297e575fb1..46dc634db8 100644
--- 
a/core/src/main/java/org/apache/accumulo/core/security/VisibilityParseException.java
+++ 
b/core/src/main/java/org/apache/accumulo/core/security/VisibilityParseException.java
@@ -22,6 +22,8 @@ import static java.nio.charset.StandardCharsets.UTF_8;
 
 import java.text.ParseException;
 
+import org.apache.accumulo.access.IllegalAccessExpressionException;
+
 /**
  * An exception thrown when a visibility string cannot be parsed.
  */
@@ -41,6 +43,15 @@ public class VisibilityParseException extends ParseException 
{
     this.visibility = new String(visibility, UTF_8);
   }
 
+  /**
+   * @since 3.1.0
+   */
+  public VisibilityParseException(IllegalAccessExpressionException e) {
+    // TODO need to look at output for this
+    super(e.getDescription(), e.getIndex());
+    this.visibility = e.getPattern();
+  }
+
   @Override
   public String getMessage() {
     return super.getMessage() + " in string '" + visibility + "' at position "
diff --git 
a/core/src/main/java/org/apache/accumulo/core/util/BadArgumentException.java 
b/core/src/main/java/org/apache/accumulo/core/util/BadArgumentException.java
index ac9cafe1e4..88e1b6f3a6 100644
--- a/core/src/main/java/org/apache/accumulo/core/util/BadArgumentException.java
+++ b/core/src/main/java/org/apache/accumulo/core/util/BadArgumentException.java
@@ -20,10 +20,17 @@ package org.apache.accumulo.core.util;
 
 import java.util.regex.PatternSyntaxException;
 
+import org.apache.accumulo.access.IllegalAccessExpressionException;
+
 public final class BadArgumentException extends PatternSyntaxException {
   private static final long serialVersionUID = 1L;
 
   public BadArgumentException(String desc, String badarg, int index) {
     super(desc, badarg, index);
   }
+
+  public BadArgumentException(IllegalAccessExpressionException e) {
+    super(e.getDescription(), e.getPattern(), e.getIndex());
+    super.initCause(e);
+  }
 }
diff --git 
a/core/src/test/java/org/apache/accumulo/core/data/constraints/VisibilityConstraintTest.java
 
b/core/src/test/java/org/apache/accumulo/core/data/constraints/VisibilityConstraintTest.java
index 70f10b9600..2f31877701 100644
--- 
a/core/src/test/java/org/apache/accumulo/core/data/constraints/VisibilityConstraintTest.java
+++ 
b/core/src/test/java/org/apache/accumulo/core/data/constraints/VisibilityConstraintTest.java
@@ -43,11 +43,13 @@ public class VisibilityConstraintTest {
   Environment env;
   Mutation mutation;
 
-  static final ColumnVisibility good = new ColumnVisibility("good");
-  static final ColumnVisibility bad = new ColumnVisibility("bad");
+  static final ColumnVisibility good = new ColumnVisibility("good|bad");
+  static final ColumnVisibility bad = new ColumnVisibility("good&bad");
 
   static final String D = "don't care";
 
+  static final List<Short> ILLEGAL = Arrays.asList((short) 1);
+
   static final List<Short> ENOAUTH = Arrays.asList((short) 2);
 
   @BeforeEach
@@ -98,4 +100,11 @@ public class VisibilityConstraintTest {
     assertEquals(ENOAUTH, vc.check(env, mutation), "unauthorized");
   }
 
+  @Test
+  public void testIllegalVisibility() {
+    mutation.put(D, D, good, D);
+    // set an illegal visibility string
+    mutation.at().family(D).qualifier(D).visibility("good&").put(D);
+    assertEquals(ILLEGAL, vc.check(env, mutation), "unauthorized");
+  }
 }
diff --git 
a/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java
 
b/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java
index e37af5b265..2723f3abe7 100644
--- 
a/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java
+++ 
b/core/src/test/java/org/apache/accumulo/core/security/ColumnVisibilityTest.java
@@ -63,6 +63,7 @@ public class ColumnVisibilityTest {
   }
 
   @Test
+  @SuppressWarnings("deprecation")
   public void testEmptyFlatten() {
     // empty visibility is valid
     new ColumnVisibility().flatten();
@@ -87,6 +88,7 @@ public class ColumnVisibilityTest {
     shouldThrow("a*b");
   }
 
+  @SuppressWarnings("deprecation")
   public void normalized(String... values) {
     for (int i = 0; i < values.length; i += 2) {
       ColumnVisibility cv = new ColumnVisibility(values[i].getBytes());
@@ -161,6 +163,7 @@ public class ColumnVisibilityTest {
   }
 
   @Test
+  @SuppressWarnings("deprecation")
   public void testToString() {
     ColumnVisibility cv = new ColumnVisibility(quote("a"));
     assertEquals("[a]", cv.toString());
@@ -171,6 +174,7 @@ public class ColumnVisibilityTest {
   }
 
   @Test
+  @SuppressWarnings("deprecation")
   public void testParseTree() {
     Node node = parse("(W)|(U&V)");
     assertNode(node, NodeType.OR, 0, 9);
@@ -179,12 +183,14 @@ public class ColumnVisibilityTest {
   }
 
   @Test
+  @SuppressWarnings("deprecation")
   public void testParseTreeWithNoChildren() {
     Node node = parse("ABC");
     assertNode(node, NodeType.TERM, 0, 3);
   }
 
   @Test
+  @SuppressWarnings("deprecation")
   public void testParseTreeWithTwoChildren() {
     Node node = parse("ABC|DEF");
     assertNode(node, NodeType.OR, 0, 7);
@@ -193,6 +199,7 @@ public class ColumnVisibilityTest {
   }
 
   @Test
+  @SuppressWarnings("deprecation")
   public void testParseTreeWithParenthesesAndTwoChildren() {
     Node node = parse("(ABC|DEF)");
     assertNode(node, NodeType.OR, 1, 8);
@@ -201,6 +208,7 @@ public class ColumnVisibilityTest {
   }
 
   @Test
+  @SuppressWarnings("deprecation")
   public void testParseTreeWithParenthesizedChildren() {
     Node node = parse("ABC|(DEF&GHI)");
     assertNode(node, NodeType.OR, 0, 13);
@@ -211,6 +219,7 @@ public class ColumnVisibilityTest {
   }
 
   @Test
+  @SuppressWarnings("deprecation")
   public void testParseTreeWithMoreParentheses() {
     Node node = parse("(W)|(U&V)");
     assertNode(node, NodeType.OR, 0, 9);
@@ -221,6 +230,7 @@ public class ColumnVisibilityTest {
   }
 
   @Test
+  @SuppressWarnings("deprecation")
   public void testEmptyParseTreesAreEqual() {
     Comparator<Node> comparator = new NodeComparator(new byte[] {});
     Node empty = new ColumnVisibility().getParseTree();
@@ -228,6 +238,7 @@ public class ColumnVisibilityTest {
   }
 
   @Test
+  @SuppressWarnings("deprecation")
   public void testParseTreesOrdering() {
     byte[] expression = "(b&c&d)|((a|m)&y&z)|(e&f)".getBytes(UTF_8);
     byte[] flattened = new ColumnVisibility(expression).flatten();
@@ -238,11 +249,13 @@ public class ColumnVisibilityTest {
     assertTrue(flat.indexOf('b') < flat.indexOf('a'), "shortest children sort 
first");
   }
 
+  @SuppressWarnings("deprecation")
   private Node parse(String s) {
     ColumnVisibility v = new ColumnVisibility(s);
     return v.getParseTree();
   }
 
+  @SuppressWarnings("deprecation")
   private void assertNode(Node node, NodeType nodeType, int start, int end) {
     assertEquals(node.type, nodeType);
     assertEquals(start, node.start);
diff --git 
a/core/src/test/java/org/apache/accumulo/core/security/VisibilityEvaluatorTest.java
 
b/core/src/test/java/org/apache/accumulo/core/security/VisibilityEvaluatorTest.java
index 637fb6877d..31ae8ea3ed 100644
--- 
a/core/src/test/java/org/apache/accumulo/core/security/VisibilityEvaluatorTest.java
+++ 
b/core/src/test/java/org/apache/accumulo/core/security/VisibilityEvaluatorTest.java
@@ -21,15 +21,12 @@ package org.apache.accumulo.core.security;
 import static org.apache.accumulo.core.security.ColumnVisibility.quote;
 import static org.junit.jupiter.api.Assertions.assertEquals;
 import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertThrows;
 import static org.junit.jupiter.api.Assertions.assertTrue;
 
-import java.util.List;
-
-import org.apache.accumulo.core.data.ArrayByteSequence;
 import org.apache.accumulo.core.util.ByteArraySet;
 import org.junit.jupiter.api.Test;
 
+@SuppressWarnings("deprecation")
 public class VisibilityEvaluatorTest {
 
   @Test
@@ -100,25 +97,6 @@ public class VisibilityEvaluatorTest {
     assertEquals("\"五十\"", quote("五十"));
   }
 
-  @Test
-  public void testUnescape() {
-    assertEquals("a\"b", VisibilityEvaluator.unescape(new 
ArrayByteSequence("a\\\"b")).toString());
-    assertEquals("a\\b", VisibilityEvaluator.unescape(new 
ArrayByteSequence("a\\\\b")).toString());
-    assertEquals("a\\\"b",
-        VisibilityEvaluator.unescape(new 
ArrayByteSequence("a\\\\\\\"b")).toString());
-    assertEquals("\\\"",
-        VisibilityEvaluator.unescape(new 
ArrayByteSequence("\\\\\\\"")).toString());
-    assertEquals("a\\b\\c\\d",
-        VisibilityEvaluator.unescape(new 
ArrayByteSequence("a\\\\b\\\\c\\\\d")).toString());
-
-    final String message = "Expected failure to unescape invalid escape 
sequence";
-    final var invalidEscapeSeqList = List.of(new ArrayByteSequence("a\\b"),
-        new ArrayByteSequence("a\\b\\c"), new ArrayByteSequence("a\"b\\"));
-
-    invalidEscapeSeqList.forEach(seq -> 
assertThrows(IllegalArgumentException.class,
-        () -> VisibilityEvaluator.unescape(seq), message));
-  }
-
   @Test
   public void testNonAscii() throws VisibilityParseException {
     VisibilityEvaluator ct = new VisibilityEvaluator(new Authorizations("五", 
"六", "八", "九", "五十"));
diff --git a/pom.xml b/pom.xml
index 901e9db280..014424cdc9 100644
--- a/pom.xml
+++ b/pom.xml
@@ -145,6 +145,7 @@
     <surefire.reuseForks>true</surefire.reuseForks>
     <unitTestMemSize>-Xmx1G</unitTestMemSize>
     <!-- dependency and plugin versions managed with properties -->
+    <version.accumulo-access>1.0.0-beta</version.accumulo-access>
     <version.auto-service>1.1.1</version.auto-service>
     <version.bouncycastle>1.78.1</version.bouncycastle>
     <version.curator>5.5.0</version.curator>
@@ -315,6 +316,11 @@
         <artifactId>commons-logging</artifactId>
         <version>1.2</version>
       </dependency>
+      <dependency>
+        <groupId>org.apache.accumulo</groupId>
+        <artifactId>accumulo-access</artifactId>
+        <version>${version.accumulo-access}</version>
+      </dependency>
       <dependency>
         <groupId>org.apache.accumulo</groupId>
         <artifactId>accumulo-compaction-coordinator</artifactId>


Reply via email to