Skip to content
Merged
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 @@ -24,9 +24,9 @@
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.clientImpl.access.BytesAccess;
import org.apache.accumulo.core.data.ArrayByteSequence;
import org.apache.accumulo.core.data.ByteSequence;
import org.apache.accumulo.core.data.Key;
Expand Down Expand Up @@ -82,7 +82,7 @@ public void convert(Key k, Value v, Consumer<ByteSequence> consumer) {
Set<ByteSequence> auths = cache.get(vis);
if (auths == null) {
var newAuths = new HashSet<ByteSequence>();
AccessExpression.findAuthorizations(vis.toArray(),
BytesAccess.findAuthorizations(vis.toArray(),
auth -> newAuths.add(new ArrayByteSequence(auth)));
cache.put(new ArrayByteSequence(vis), newAuths);
auths = newAuths;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;

import org.apache.accumulo.access.AccessEvaluator;
import org.apache.accumulo.access.InvalidAccessExpressionException;
import org.apache.accumulo.core.client.AccumuloException;
import org.apache.accumulo.core.client.AccumuloSecurityException;
Expand All @@ -52,6 +51,7 @@
import org.apache.accumulo.core.client.Durability;
import org.apache.accumulo.core.client.TimedOutException;
import org.apache.accumulo.core.clientImpl.ClientTabletCache.TabletServerMutations;
import org.apache.accumulo.core.clientImpl.access.BytesAccess;
import org.apache.accumulo.core.clientImpl.thrift.TInfo;
import org.apache.accumulo.core.clientImpl.thrift.ThriftSecurityException;
import org.apache.accumulo.core.data.ByteSequence;
Expand Down Expand Up @@ -97,7 +97,7 @@ public class ConditionalWriterImpl implements ConditionalWriter {
private static final int MAX_SLEEP = 30000;

private final Authorizations auths;
private final AccessEvaluator accessEvaluator;
private final BytesAccess.BytesEvaluator accessEvaluator;
private final Map<Text,Boolean> cache = Collections.synchronizedMap(new LRUMap<>(1000));
private final ClientContext context;
private final ClientTabletCache locator;
Expand Down Expand Up @@ -375,7 +375,7 @@ private TabletServerMutations<QCMutation> dequeue(String location) {
this.config = config;
this.context = context;
this.auths = config.getAuthorizations();
this.accessEvaluator = AccessEvaluator.of(config.getAuthorizations().toAccessAuthorizations());
this.accessEvaluator = BytesAccess.newEvaluator(config.getAuthorizations());
this.threadPool = context.threadPools().createScheduledExecutorService(
config.getMaxWriteThreads(), CONDITIONAL_WRITER_POOL.poolName);
this.locator = new SyncingClientTabletCache(context, tableId);
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
* 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
*
* https://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.accumulo.core.clientImpl.access;

import static java.nio.charset.StandardCharsets.ISO_8859_1;

import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.function.Consumer;

import org.apache.accumulo.access.Access;
import org.apache.accumulo.access.AccessEvaluator;
import org.apache.accumulo.core.data.ArrayByteSequence;
import org.apache.accumulo.core.security.AuthorizationContainer;
import org.apache.accumulo.core.security.Authorizations;

/**
* All Accumulo Access APIs are String based. Accumulo's legacy APIs for access control are all
* based on byte[]. This class maps those legacy byte[] based APIs to use the Accumulo Access string
* based APIs.
*
* <p>
* This mapping is done by using ISO_8859_1 to convert byte[] to String and vice versa. ISO_8859_1
* is used because it maps each unsigned integer in a byte array directly to the same unsigned
* integer in the strings char array. This preserves the behavior of Accumulo legacy APIs by making
* Accumulo Access operate on the exact same data as the legacy APIs did.
*
* <p>
* All transformations using ISO_8859_1 should remain completely within this class and never escape.
* For example if a string escaped this class it could lead to an overall situation where
* {@code new String(bytes,ISO_8859_1).getBytes(UTF_8)} accidentally happens.
*
* <p>
* In addition to using ISO_8859_1, an instance of Accumulo Access is created that does no
* validation of authorizations. By default, Accumulo Access would reject some chars which
* conceptually would reject some bytes. The legacy Accumulo APIs accepted any bytes.
*
* <p>
* This class is meant to serve as a bridge between legacy behavior that accepted any byte in an
* access expression and newer default behavior in Accumulo Access that only accepts valid Unicode.
*/
public class BytesAccess {

private static final Access ACCESS =
Access.builder().authorizationValidator((auth, authChars) -> true).build();

public static void validate(byte[] expression) {
ACCESS.validateExpression(new String(expression, ISO_8859_1));
}

public static byte[] quote(byte[] auth) {
return ACCESS.quote(new String(auth, ISO_8859_1)).getBytes(ISO_8859_1);
}

public static String quote(String auth) {
// TODO is this safe? does not go through a byte array
return ACCESS.quote(auth);
}

public static void findAuthorizations(byte[] expression, Consumer<byte[]> consumer) {
ACCESS.findAuthorizations(new String(expression, ISO_8859_1),
authString -> consumer.accept(authString.getBytes(ISO_8859_1)));
}

public static class BytesEvaluator {

private final AccessEvaluator evaluator;

private BytesEvaluator(AccessEvaluator evaluator) {
this.evaluator = evaluator;
}

public boolean canAccess(byte[] expression) {
return evaluator.canAccess(new String(expression, ISO_8859_1));
}
}

public static BytesEvaluator newEvaluator(Authorizations auths) {
List<byte[]> bytesAuths = auths.getAuthorizations();
Set<String> stringAuths = new HashSet<>(bytesAuths.size());
for (var auth : bytesAuths) {
stringAuths.add(new String(auth, ISO_8859_1));
}
return new BytesEvaluator(ACCESS.newEvaluator(ACCESS.newAuthorizations(stringAuths)));
}

public static BytesEvaluator newEvaluator(AuthorizationContainer authContainer) {
AccessEvaluator.Authorizer authorizer = authString -> authContainer
.contains(new ArrayByteSequence(authString.getBytes(ISO_8859_1)));
return new BytesEvaluator(ACCESS.newEvaluator(authorizer));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,8 @@
import java.util.HashSet;
import java.util.List;

import org.apache.accumulo.access.AccessEvaluator;
import org.apache.accumulo.access.InvalidAccessExpressionException;
import org.apache.accumulo.core.data.ArrayByteSequence;
import org.apache.accumulo.core.clientImpl.access.BytesAccess;
import org.apache.accumulo.core.data.ColumnUpdate;
import org.apache.accumulo.core.data.Mutation;

Expand Down Expand Up @@ -64,7 +63,7 @@ public List<Short> check(Environment env, Mutation mutation) {
ok = new HashSet<>();
}

AccessEvaluator ve = null;
BytesAccess.BytesEvaluator ve = null;

for (ColumnUpdate update : updates) {

Expand All @@ -79,7 +78,7 @@ public List<Short> check(Environment env, Mutation mutation) {

if (ve == null) {
var authContainer = env.getAuthorizationsContainer();
ve = AccessEvaluator.of(auth -> authContainer.contains(new ArrayByteSequence(auth)));
ve = BytesAccess.newEvaluator(authContainer);
}

if (!ve.canAccess(cv)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,9 @@
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.InvalidAccessExpressionException;
import org.apache.accumulo.core.client.IteratorSetting;
import org.apache.accumulo.core.clientImpl.access.BytesAccess;
import org.apache.accumulo.core.conf.ConfigurationTypeHelper;
import org.apache.accumulo.core.data.ByteSequence;
import org.apache.accumulo.core.data.Key;
Expand Down Expand Up @@ -102,7 +101,7 @@ public abstract class TransformingIterator extends WrappingIterator implements O
protected Collection<ByteSequence> seekColumnFamilies;
protected boolean seekColumnFamiliesInclusive;

private AccessEvaluator ve = null;
private BytesAccess.BytesEvaluator ve = null;
private LRUMap<ByteSequence,Boolean> visibleCache = null;
private LRUMap<ByteSequence,Boolean> parsedVisibilitiesCache = null;
private long maxBufferSize;
Expand All @@ -118,7 +117,7 @@ public void init(SortedKeyValueIterator<Key,Value> source, Map<String,String> op
if (scanning) {
String auths = options.get(AUTH_OPT);
if (auths != null && !auths.isEmpty()) {
ve = AccessEvaluator.of(new Authorizations(auths.getBytes(UTF_8)).toAccessAuthorizations());
ve = BytesAccess.newEvaluator(new Authorizations(auths.getBytes(UTF_8)));
visibleCache = new LRUMap<>(100);
}
}
Expand Down Expand Up @@ -412,7 +411,7 @@ protected boolean canSee(Key key) {
Boolean parsed = parsedVisibilitiesCache.get(visibility);
if (parsed == null) {
try {
AccessExpression.validate(visibility.toArray());
BytesAccess.validate(visibility.toArray());
parsedVisibilitiesCache.put(visibility, Boolean.TRUE);
} catch (InvalidAccessExpressionException e) {
log.error("Parse error after transformation : {}", visibility);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,10 +23,9 @@
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.InvalidAccessExpressionException;
import org.apache.accumulo.core.client.IteratorSetting;
import org.apache.accumulo.core.clientImpl.access.BytesAccess;
import org.apache.accumulo.core.data.ArrayByteSequence;
import org.apache.accumulo.core.data.ByteSequence;
import org.apache.accumulo.core.data.Key;
Expand All @@ -45,7 +44,7 @@
*/
public class VisibilityFilter extends Filter implements OptionDescriber {

private AccessEvaluator accessEvaluator;
private BytesAccess.BytesEvaluator accessEvaluator;
protected Map<ByteSequence,Boolean> cache;
private final ArrayByteSequence testVis = new ArrayByteSequence(new byte[0]);

Expand All @@ -68,7 +67,7 @@ public void init(SortedKeyValueIterator<Key,Value> source, Map<String,String> op
Authorizations authObj = auths == null || auths.isEmpty() ? new Authorizations()
: new Authorizations(auths.getBytes(UTF_8));

this.accessEvaluator = AccessEvaluator.of(authObj.toAccessAuthorizations());
this.accessEvaluator = BytesAccess.newEvaluator(authObj);
}
this.cache = new LRUMap<>(1000);
}
Expand Down Expand Up @@ -96,7 +95,7 @@ public boolean accept(Key k, Value v) {
}
final ArrayByteSequence copy = new ArrayByteSequence(testVis);
try {
AccessExpression.validate(copy.toArray());
BytesAccess.validate(copy.toArray());
// cache a copy of testVis
cache.put(copy, true);
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@
*/
package org.apache.accumulo.core.iteratorsImpl.system;

import org.apache.accumulo.access.AccessEvaluator;
import org.apache.accumulo.access.InvalidAccessExpressionException;
import org.apache.accumulo.core.clientImpl.access.BytesAccess;
import org.apache.accumulo.core.data.ArrayByteSequence;
import org.apache.accumulo.core.data.ByteSequence;
import org.apache.accumulo.core.data.Key;
Expand All @@ -41,7 +41,7 @@
* class.
*/
public class VisibilityFilter extends SynchronizedServerFilter {
protected final AccessEvaluator ve;
protected final BytesAccess.BytesEvaluator ve;
protected final ArrayByteSequence defaultVisibility;
protected final LRUMap<ByteSequence,Boolean> cache;
protected final Authorizations authorizations;
Expand All @@ -53,7 +53,7 @@ public class VisibilityFilter extends SynchronizedServerFilter {
private VisibilityFilter(SortedKeyValueIterator<Key,Value> iterator,
Authorizations authorizations, byte[] defaultVisibility) {
super(iterator);
this.ve = AccessEvaluator.of(authorizations.toAccessAuthorizations());
this.ve = BytesAccess.newEvaluator(authorizations);
this.authorizations = authorizations;
this.defaultVisibility = new ArrayByteSequence(defaultVisibility);
this.cache = new LRUMap<>(1000);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -388,21 +388,4 @@ public String serialize() {

return sb.toString();
}

/**
* Converts to an Accumulo Access Authorizations object.
*
* @since 4.0.0
*/
public org.apache.accumulo.access.Authorizations toAccessAuthorizations() {
if (auths.isEmpty()) {
return org.apache.accumulo.access.Authorizations.of();
} 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);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,8 +29,10 @@
import java.util.TreeSet;
import java.util.function.Supplier;

import org.apache.accumulo.access.Access;
import org.apache.accumulo.access.AccessExpression;
import org.apache.accumulo.access.InvalidAccessExpressionException;
import org.apache.accumulo.core.clientImpl.access.BytesAccess;
import org.apache.accumulo.core.data.ArrayByteSequence;
import org.apache.accumulo.core.data.ByteSequence;
import org.apache.accumulo.core.util.BadArgumentException;
Expand Down Expand Up @@ -525,7 +527,7 @@ public ColumnVisibility(Text expression) {
public ColumnVisibility(byte[] expression) {
this.expression = expression;
try {
AccessExpression.validate(this.expression);
BytesAccess.validate(this.expression);
} catch (InvalidAccessExpressionException e) {
// This is thrown for compatability with the exception this class used to throw when it parsed
// exceptions itself.
Expand Down Expand Up @@ -607,11 +609,11 @@ public Node getParseTree() {
*
* @param term term to quote
* @return quoted term (unquoted if unnecessary)
* @deprecated use {@link AccessExpression#quote(String)}
* @deprecated use {@link Access#quote(String)}
*/
@Deprecated(since = "4.0.0")
public static String quote(String term) {
return AccessExpression.quote(term);
return BytesAccess.quote(term);
}

/**
Expand All @@ -621,10 +623,10 @@ public static String quote(String term) {
* @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 use {@link Access#quote(String)}
*/
@Deprecated(since = "4.0.0")
public static byte[] quote(byte[] term) {
return AccessExpression.quote(term);
return BytesAccess.quote(term);
}
}
Loading