Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,14 @@
import org.antlr.v4.runtime.tree.ParseTree;
import org.antlr.v4.runtime.tree.TerminalNode;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.access.Authorizations;
import org.apache.accumulo.access.InvalidAccessExpressionException;
import org.apache.accumulo.access.grammars.AccessExpressionParser.Access_expressionContext;
import org.apache.accumulo.access.grammars.AccessExpressionParser.Access_tokenContext;
import org.apache.accumulo.access.grammars.AccessExpressionParser.And_expressionContext;
import org.apache.accumulo.access.grammars.AccessExpressionParser.And_operatorContext;
import org.apache.accumulo.access.grammars.AccessExpressionParser.Or_expressionContext;
import org.apache.accumulo.access.grammars.AccessExpressionParser.Or_operatorContext;
import org.apache.accumulo.access.Authorizations;

public class AccessExpressionAntlrEvaluator {

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,11 +29,11 @@
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.accumulo.access.Authorizations;
import org.apache.accumulo.access.antlr.TestDataLoader;
import org.apache.accumulo.access.antlr4.AccessExpressionAntlrEvaluator;
import org.apache.accumulo.access.antlr4.AccessExpressionAntlrParser;
import org.apache.accumulo.access.grammars.AccessExpressionParser.Access_expressionContext;
import org.apache.accumulo.access.Authorizations;
import org.openjdk.jmh.annotations.Benchmark;
import org.openjdk.jmh.annotations.Mode;
import org.openjdk.jmh.annotations.Scope;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import org.antlr.v4.runtime.Recognizer;
import org.apache.accumulo.access.AccessEvaluator;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.access.Authorizations;
import org.apache.accumulo.access.InvalidAccessExpressionException;
import org.apache.accumulo.access.antlr.TestDataLoader;
import org.apache.accumulo.access.antlr.TestDataLoader.ExpectedResult;
Expand All @@ -51,6 +50,7 @@
import org.apache.accumulo.access.grammars.AccessExpressionLexer;
import org.apache.accumulo.access.grammars.AccessExpressionParser;
import org.apache.accumulo.access.grammars.AccessExpressionParser.Access_expressionContext;
import org.apache.accumulo.access.Authorizations;
import org.junit.jupiter.api.Test;

public class Antlr4Tests {
Expand Down Expand Up @@ -144,7 +144,7 @@ public void testCompareAntlrEvaluationAgainstAccessEvaluatorImpl() throws Except

List<Authorizations> authSets = Stream.of(testSet.auths)
.map(a -> Authorizations.of(Set.of(a))).collect(Collectors.toList());
AccessEvaluator evaluator = AccessEvaluator.of(authSets);
AccessEvaluator evaluator = Authorizations.evaluator(authSets);
AccessExpressionAntlrEvaluator antlr = new AccessExpressionAntlrEvaluator(authSets);

for (TestExpressions test : testSet.tests) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,6 @@
*/
package org.apache.accumulo.access;

import java.util.Collection;

import org.apache.accumulo.access.impl.AccessEvaluatorImpl;
import org.apache.accumulo.access.impl.MultiAccessEvaluatorImpl;

Expand All @@ -32,7 +30,7 @@
*
* <pre>
* {@code
* var evaluator = AccessEvaluator.of("ALPHA", "OMEGA");
* var evaluator = Authorizations.of(Set.of("ALPHA", "OMEGA")).evaluator();
*
* System.out.println(evaluator.canAccess("ALPHA&BETA")); // should print 'false'
* System.out.println(evaluator.canAccess("(ALPHA|BETA)&(OMEGA|EPSILON)")); // should print 'true'
Expand Down Expand Up @@ -80,88 +78,4 @@ public sealed interface AccessEvaluator permits AccessEvaluatorImpl, MultiAccess
*/
boolean canAccess(AccessExpression accessExpression);

/**
* Creates an AccessEvaluator from an Authorizations object
*
* @param authorizations auths to use in the AccessEvaluator
* @return AccessEvaluator object
*/
static AccessEvaluator of(Authorizations authorizations) {
return new AccessEvaluatorImpl(authorizations);
}

/**
* Creates an AccessEvaluator from an Authorizer object
*
* @param authorizer authorizer to use in the AccessEvaluator
* @return AccessEvaluator object
*/
static AccessEvaluator of(Authorizer authorizer) {
return new AccessEvaluatorImpl(authorizer);
}

/**
* Allows providing multiple sets of authorizations. Each expression will be evaluated
* independently against each set of authorizations and will only be deemed accessible if
* accessible for all. For example the following code would print false, true, and then false.
*
* <pre>
* {@code
* Collection<Authorizations> authSets =
* List.of(Authorizations.of("A", "B"), Authorizations.of("C", "D"));
* var evaluator = AccessEvaluator.of(authSets);
*
* System.out.println(evaluator.canAccess("A"));
* System.out.println(evaluator.canAccess("A|D"));
* System.out.println(evaluator.canAccess("A&D"));
*
* }
* </pre>
*
* <p>
* The following table shows how each expression in the example above will evaluate for each
* authorization set. In order to return true for {@code canAccess()} the expression must evaluate
* to true for each authorization set.
*
* <table>
* <caption>Evaluations</caption>
* <tr>
* <td></td>
* <td>[A,B]</td>
* <td>[C,D]</td>
* </tr>
* <tr>
* <td>A</td>
* <td>True</td>
* <td>False</td>
* </tr>
* <tr>
* <td>A|D</td>
* <td>True</td>
* <td>True</td>
* </tr>
* <tr>
* <td>A&amp;D</td>
* <td>False</td>
* <td>False</td>
* </tr>
*
* </table>
*
*
*
*/
static AccessEvaluator of(Collection<Authorizations> authorizationSets) {
return MultiAccessEvaluatorImpl.of(authorizationSets);
}

/**
* An interface that is used to check if an authorization seen in an access expression is
* authorized.
*
* @since 1.0.0
*/
interface Authorizer {
boolean isAuthorized(String auth);
}
}
144 changes: 92 additions & 52 deletions core/src/main/java/org/apache/accumulo/access/Authorizations.java
Original file line number Diff line number Diff line change
Expand Up @@ -19,66 +19,31 @@
package org.apache.accumulo.access;

import java.io.Serializable;
import java.util.Iterator;
import java.util.Collection;
import java.util.Set;

/**
* An immutable collection of authorization strings.
*
* <p>
* Instances of this class are thread-safe.
*
* <p>
* Note: The underlying implementation uses UTF-8 when converting between bytes and Strings.
*
* @since 1.0.0
*/
public final class Authorizations implements Iterable<String>, Serializable {

private static final long serialVersionUID = 1L;

private static final Authorizations EMPTY = new Authorizations(Set.of());
import org.apache.accumulo.access.impl.AccessEvaluatorImpl;
import org.apache.accumulo.access.impl.AuthorizationsImpl;
import org.apache.accumulo.access.impl.MultiAccessEvaluatorImpl;

private final Set<String> authorizations;

private Authorizations(Set<String> authorizations) {
this.authorizations = Set.copyOf(authorizations);
}
public sealed interface Authorizations extends Iterable<String>, Serializable
permits AuthorizationsImpl {

/**
* Returns the set of authorization strings in this Authorization object
* An interface that is used to check if an authorization seen in an access expression is
* authorized.
*
* @return immutable set of authorization strings
* @since 1.0.0
*/
public Set<String> asSet() {
return authorizations;
}

@Override
public boolean equals(Object o) {
if (o instanceof Authorizations) {
var oa = (Authorizations) o;
return authorizations.equals(oa.authorizations);
}

return false;
}

@Override
public int hashCode() {
return authorizations.hashCode();
}

@Override
public String toString() {
return authorizations.toString();
interface Authorizer {
boolean isAuthorized(String auth);
}

/**
* @return a pre-allocated empty Authorizations object
*/
public static Authorizations of() {
return EMPTY;
return AuthorizationsImpl.EMPTY;
}

/**
Expand All @@ -89,14 +54,89 @@ public static Authorizations of() {
*/
public static Authorizations of(Set<String> authorizations) {
if (authorizations.isEmpty()) {
return EMPTY;
return AuthorizationsImpl.EMPTY;
} else {
return new Authorizations(authorizations);
return new AuthorizationsImpl(authorizations);
}
}

@Override
public Iterator<String> iterator() {
return authorizations.iterator();
/**
* Returns the set of authorization strings in this Authorization object
*
* @return immutable set of authorization strings
*/
public Set<String> asSet();

/**
* Creates an AccessEvaluator from an Authorizations object
*
* @return AccessEvaluator object
*/
AccessEvaluator evaluator();

/**
* Creates an AccessEvaluator from an Authorizer object
*
* @param authorizer authorizer to use in the AccessEvaluator
* @return AccessEvaluator object
*/
static AccessEvaluator using(Authorizer authorizer) {
return new AccessEvaluatorImpl(authorizer);
}

/**
* Allows providing multiple sets of authorizations. Each expression will be evaluated
* independently against each set of authorizations and will only be deemed accessible if
* accessible for all. For example the following code would print false, true, and then false.
*
* <pre>
* {@code
* Collection<Authorizations> authSets =
* List.of(Authorizations.of("A", "B"), Authorizations.of("C", "D"));
* var evaluator = AccessEvaluator.of(authSets);
*
* System.out.println(evaluator.canAccess("A"));
* System.out.println(evaluator.canAccess("A|D"));
* System.out.println(evaluator.canAccess("A&D"));
*
* }
* </pre>
*
* <p>
* The following table shows how each expression in the example above will evaluate for each
* authorization set. In order to return true for {@code canAccess()} the expression must evaluate
* to true for each authorization set.
*
* <table>
* <caption>Evaluations</caption>
* <tr>
* <td></td>
* <td>[A,B]</td>
* <td>[C,D]</td>
* </tr>
* <tr>
* <td>A</td>
* <td>True</td>
* <td>False</td>
* </tr>
* <tr>
* <td>A|D</td>
* <td>True</td>
* <td>True</td>
* </tr>
* <tr>
* <td>A&amp;D</td>
* <td>False</td>
* <td>False</td>
* </tr>
*
* </table>
*
*
*
*/
static AccessEvaluator evaluator(Collection<Authorizations> authorizationSets) {
return new MultiAccessEvaluatorImpl(authorizationSets);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@

import org.apache.accumulo.access.AccessEvaluator;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.access.Authorizations;
import org.apache.accumulo.access.Authorizations.Authorizer;
import org.apache.accumulo.access.InvalidAccessExpressionException;

public final class AccessEvaluatorImpl implements AccessEvaluator {
Expand All @@ -47,7 +47,7 @@ public AccessEvaluatorImpl(Authorizer authorizationChecker) {
/**
* Create an AccessEvaluatorImpl using a collection of authorizations
*/
public AccessEvaluatorImpl(Authorizations authorizations) {
public AccessEvaluatorImpl(AuthorizationsImpl authorizations) {
var authsSet = authorizations.asSet();
final Set<BytesWrapper> authBytes = new HashSet<>(authsSet.size());
for (String authorization : authsSet) {
Expand Down
Loading