HBASE-7663 [Per-KV security] Visibility labels

git-svn-id: https://svn.apache.org/repos/asf/hbase/trunk@1543314 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
anoopsamjohn 2013-11-19 05:39:47 +00:00
parent dc20322a6a
commit 5a6a0fd78b
46 changed files with 12402 additions and 121 deletions

View File

@ -61,7 +61,7 @@ import org.apache.hadoop.hbase.util.Bytes;
*/
@InterfaceAudience.Public
@InterfaceStability.Stable
public class Get extends OperationWithAttributes
public class Get extends Query
implements Row, Comparable<Row> {
private byte [] row = null;

View File

@ -36,7 +36,11 @@ import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.KeyValue;
import org.apache.hadoop.hbase.KeyValueUtil;
import org.apache.hadoop.hbase.Tag;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.io.HeapSize;
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.security.visibility.CellVisibility;
import org.apache.hadoop.hbase.security.visibility.VisibilityConstants;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.ClassSize;
@ -289,6 +293,26 @@ public abstract class Mutation extends OperationWithAttributes implements Row, C
return clusterIds;
}
/**
* Sets the visibility expression associated with cells in this Mutation.
* It is illegal to set <code>CellVisibility</code> on <code>Delete</code> mutation.
* @param expression
*/
public void setCellVisibility(CellVisibility expression) {
this.setAttribute(VisibilityConstants.VISIBILITY_LABELS_ATTR_KEY, ProtobufUtil
.toCellVisibility(expression).toByteArray());
}
/**
* @return CellVisibility associated with cells in this Mutation.
* @throws DeserializationException
*/
public CellVisibility getCellVisibility() throws DeserializationException {
byte[] cellVisibilityBytes = this.getAttribute(VisibilityConstants.VISIBILITY_LABELS_ATTR_KEY);
if (cellVisibilityBytes == null) return null;
return ProtobufUtil.toCellVisibility(cellVisibilityBytes);
}
/**
* Number of KeyValues carried by this Mutation.
* @return the total number of KeyValues

View File

@ -0,0 +1,49 @@
/**
* 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.hadoop.hbase.client;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.security.visibility.Authorizations;
import org.apache.hadoop.hbase.security.visibility.VisibilityConstants;
@InterfaceAudience.Public
@InterfaceStability.Evolving
public abstract class Query extends OperationWithAttributes {
/**
* Sets the authorizations to be used by this Query
* @param authorizations
*/
public void setAuthorizations(Authorizations authorizations) {
this.setAttribute(VisibilityConstants.VISIBILITY_LABELS_ATTR_KEY, ProtobufUtil
.toAuthorizations(authorizations).toByteArray());
}
/**
* @return The authorizations this Query is associated with.
* @throws DeserializationException
*/
public Authorizations getAuthorizations() throws DeserializationException {
byte[] authorizationsBytes = this.getAttribute(VisibilityConstants.VISIBILITY_LABELS_ATTR_KEY);
if (authorizationsBytes == null) return null;
return ProtobufUtil.toAuthorizations(authorizationsBytes);
}
}

View File

@ -81,7 +81,7 @@ import java.util.TreeSet;
*/
@InterfaceAudience.Public
@InterfaceStability.Stable
public class Scan extends OperationWithAttributes {
public class Scan extends Query {
private static final String RAW_ATTR = "_raw_";
private static final String ISOLATION_LEVEL = "_isolationlevel_";

View File

@ -119,6 +119,8 @@ import org.apache.hadoop.hbase.security.access.Permission;
import org.apache.hadoop.hbase.security.access.TablePermission;
import org.apache.hadoop.hbase.security.access.UserPermission;
import org.apache.hadoop.hbase.security.token.AuthenticationTokenIdentifier;
import org.apache.hadoop.hbase.security.visibility.Authorizations;
import org.apache.hadoop.hbase.security.visibility.CellVisibility;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.DynamicClassLoader;
import org.apache.hadoop.hbase.util.Methods;
@ -2464,4 +2466,89 @@ public final class ProtobufUtil {
return tableNames;
}
/**
* Convert a protocol buffer CellVisibility to a client CellVisibility
*
* @param proto
* @return the converted client CellVisibility
*/
public static CellVisibility toCellVisibility(ClientProtos.CellVisibility proto) {
if (proto == null) return null;
return new CellVisibility(proto.getExpression());
}
/**
* Convert a protocol buffer CellVisibility bytes to a client CellVisibility
*
* @param protoBytes
* @return the converted client CellVisibility
* @throws DeserializationException
*/
public static CellVisibility toCellVisibility(byte[] protoBytes) throws DeserializationException {
if (protoBytes == null) return null;
ClientProtos.CellVisibility.Builder builder = ClientProtos.CellVisibility.newBuilder();
ClientProtos.CellVisibility proto = null;
try {
proto = builder.mergeFrom(protoBytes).build();
} catch (InvalidProtocolBufferException e) {
throw new DeserializationException(e);
}
return toCellVisibility(proto);
}
/**
* Create a protocol buffer CellVisibility based on a client CellVisibility.
*
* @param cellVisibility
* @return a protocol buffer CellVisibility
*/
public static ClientProtos.CellVisibility toCellVisibility(CellVisibility cellVisibility) {
ClientProtos.CellVisibility.Builder builder = ClientProtos.CellVisibility.newBuilder();
builder.setExpression(cellVisibility.getExpression());
return builder.build();
}
/**
* Convert a protocol buffer Authorizations to a client Authorizations
*
* @param proto
* @return the converted client Authorizations
*/
public static Authorizations toAuthorizations(ClientProtos.Authorizations proto) {
if (proto == null) return null;
return new Authorizations(proto.getLabelList());
}
/**
* Convert a protocol buffer Authorizations bytes to a client Authorizations
*
* @param protoBytes
* @return the converted client Authorizations
* @throws DeserializationException
*/
public static Authorizations toAuthorizations(byte[] protoBytes) throws DeserializationException {
if (protoBytes == null) return null;
ClientProtos.Authorizations.Builder builder = ClientProtos.Authorizations.newBuilder();
ClientProtos.Authorizations proto = null;
try {
proto = builder.mergeFrom(protoBytes).build();
} catch (InvalidProtocolBufferException e) {
throw new DeserializationException(e);
}
return toAuthorizations(proto);
}
/**
* Create a protocol buffer Authorizations based on a client Authorizations.
*
* @param authorizations
* @return a protocol buffer Authorizations
*/
public static ClientProtos.Authorizations toAuthorizations(Authorizations authorizations) {
ClientProtos.Authorizations.Builder builder = ClientProtos.Authorizations.newBuilder();
for (String label : authorizations.getLabels()) {
builder.addLabel(label);
}
return builder.build();
}
}

View File

@ -0,0 +1,56 @@
/**
* 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.hadoop.hbase.security.visibility;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
/**
* This class contains visibility labels associated with a Scan/Get deciding which all labeled data
* current scan/get can access.
*/
@InterfaceAudience.Public
@InterfaceStability.Stable
public class Authorizations {
private List<String> labels;
public Authorizations(String... labels) {
this.labels = new ArrayList<String>(labels.length);
for (String label : labels) {
this.labels.add(label);
}
}
public Authorizations(List<String> labels) {
this.labels = labels;
}
public List<String> getLabels() {
return Collections.unmodifiableList(this.labels);
}
@Override
public String toString() {
return this.labels.toString();
}
}

View File

@ -0,0 +1,44 @@
/**
* 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.hadoop.hbase.security.visibility;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
/**
* This contains a visibility expression which can be associated with a cell. When it is set with a
* Mutation, all the cells in that mutation will get associated with this expression. A visibility
* expression can contain visibility labels combined with logical operators AND(&), OR(|) and NOT(!)
*/
@InterfaceAudience.Public
@InterfaceStability.Evolving
public class CellVisibility {
private String expression;
public CellVisibility(String expression) {
this.expression = expression;
}
/**
* @return The visibility expression
*/
public String getExpression() {
return this.expression;
}
}

View File

@ -0,0 +1,33 @@
/*
* 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.hadoop.hbase.security.visibility;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.hbase.DoNotRetryIOException;
@InterfaceAudience.Public
@InterfaceStability.Evolving
public class InvalidLabelException extends DoNotRetryIOException {
private static final long serialVersionUID = 1L;
public InvalidLabelException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,33 @@
/*
* 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.hadoop.hbase.security.visibility;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.hbase.DoNotRetryIOException;
@InterfaceAudience.Public
@InterfaceStability.Evolving
public class LabelAlreadyExistsException extends DoNotRetryIOException {
private static final long serialVersionUID = 1L;
public LabelAlreadyExistsException(String msg) {
super(msg);
}
}

View File

@ -0,0 +1,207 @@
/**
* 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.hadoop.hbase.security.visibility;
import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABELS_TABLE_NAME;
import java.io.IOException;
import java.util.Map;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.coprocessor.Batch;
import org.apache.hadoop.hbase.ipc.BlockingRpcCallback;
import org.apache.hadoop.hbase.ipc.ServerRpcController;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.GetAuthsRequest;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.GetAuthsResponse;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.SetAuthsRequest;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabel;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsRequest;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsResponse;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsService;
import org.apache.hadoop.hbase.util.Bytes;
import com.google.protobuf.ServiceException;
import com.google.protobuf.ZeroCopyLiteralByteString;
/**
* Utility client for doing visibility labels admin operations.
*/
@InterfaceAudience.Public
@InterfaceStability.Evolving
public class VisibilityClient {
/**
* Utility method for adding label to the system.
*
* @param conf
* @param label
* @return VisibilityLabelsResponse
* @throws Throwable
*/
public static VisibilityLabelsResponse addLabel(Configuration conf, final String label)
throws Throwable {
return addLabels(conf, new String[] { label });
}
/**
* Utility method for adding labels to the system.
*
* @param conf
* @param labels
* @return VisibilityLabelsResponse
* @throws Throwable
*/
public static VisibilityLabelsResponse addLabels(Configuration conf, final String[] labels)
throws Throwable {
HTable ht = null;
try {
ht = new HTable(conf, LABELS_TABLE_NAME.getName());
Batch.Call<VisibilityLabelsService, VisibilityLabelsResponse> callable =
new Batch.Call<VisibilityLabelsService, VisibilityLabelsResponse>() {
ServerRpcController controller = new ServerRpcController();
BlockingRpcCallback<VisibilityLabelsResponse> rpcCallback =
new BlockingRpcCallback<VisibilityLabelsResponse>();
public VisibilityLabelsResponse call(VisibilityLabelsService service) throws IOException {
VisibilityLabelsRequest.Builder builder = VisibilityLabelsRequest.newBuilder();
for (String label : labels) {
if (label.length() > 0) {
VisibilityLabel.Builder newBuilder = VisibilityLabel.newBuilder();
newBuilder.setLabel(ZeroCopyLiteralByteString.wrap(Bytes.toBytes(label)));
builder.addVisLabel(newBuilder.build());
}
}
service.addLabels(controller, builder.build(), rpcCallback);
return rpcCallback.get();
}
};
Map<byte[], VisibilityLabelsResponse> result = ht.coprocessorService(
VisibilityLabelsService.class, HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY,
callable);
return result.values().iterator().next(); // There will be exactly one region for labels
// table and so one entry in result Map.
} finally {
if (ht != null) {
ht.close();
}
}
}
/**
* Sets given labels globally authorized for the user.
* @param conf
* @param auths
* @param user
* @return VisibilityLabelsResponse
* @throws Throwable
*/
public static VisibilityLabelsResponse setAuths(Configuration conf, final String[] auths,
final String user) throws Throwable {
return setOrClearAuths(conf, auths, user, true);
}
/**
* @param conf
* @param user
* @return labels, the given user is globally authorized for.
* @throws Throwable
*/
public static GetAuthsResponse getAuths(Configuration conf, final String user) throws Throwable {
HTable ht = null;
try {
ht = new HTable(conf, LABELS_TABLE_NAME.getName());
Batch.Call<VisibilityLabelsService, GetAuthsResponse> callable =
new Batch.Call<VisibilityLabelsService, GetAuthsResponse>() {
ServerRpcController controller = new ServerRpcController();
BlockingRpcCallback<GetAuthsResponse> rpcCallback =
new BlockingRpcCallback<GetAuthsResponse>();
public GetAuthsResponse call(VisibilityLabelsService service) throws IOException {
GetAuthsRequest.Builder getAuthReqBuilder = GetAuthsRequest.newBuilder();
getAuthReqBuilder.setUser(ZeroCopyLiteralByteString.wrap(Bytes.toBytes(user)));
service.getAuths(controller, getAuthReqBuilder.build(), rpcCallback);
return rpcCallback.get();
}
};
Map<byte[], GetAuthsResponse> result = ht.coprocessorService(VisibilityLabelsService.class,
HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY, callable);
return result.values().iterator().next(); // There will be exactly one region for labels
// table and so one entry in result Map.
} finally {
if (ht != null) {
ht.close();
}
}
}
/**
* Removes given labels from user's globally authorized list of labels.
* @param conf
* @param auths
* @param user
* @return VisibilityLabelsResponse
* @throws Throwable
*/
public static VisibilityLabelsResponse clearAuths(Configuration conf, final String[] auths,
final String user) throws Throwable {
return setOrClearAuths(conf, auths, user, false);
}
private static VisibilityLabelsResponse setOrClearAuths(Configuration conf, final String[] auths,
final String user, final boolean setOrClear) throws IOException, ServiceException, Throwable {
HTable ht = null;
try {
ht = new HTable(conf, LABELS_TABLE_NAME.getName());
Batch.Call<VisibilityLabelsService, VisibilityLabelsResponse> callable =
new Batch.Call<VisibilityLabelsService, VisibilityLabelsResponse>() {
ServerRpcController controller = new ServerRpcController();
BlockingRpcCallback<VisibilityLabelsResponse> rpcCallback =
new BlockingRpcCallback<VisibilityLabelsResponse>();
public VisibilityLabelsResponse call(VisibilityLabelsService service) throws IOException {
SetAuthsRequest.Builder setAuthReqBuilder = SetAuthsRequest.newBuilder();
setAuthReqBuilder.setUser(ZeroCopyLiteralByteString.wrap(Bytes.toBytes(user)));
for (String auth : auths) {
if (auth.length() > 0) {
setAuthReqBuilder.addAuth(ZeroCopyLiteralByteString.wrap(Bytes.toBytes(auth)));
}
}
if (setOrClear) {
service.setAuths(controller, setAuthReqBuilder.build(), rpcCallback);
} else {
service.clearAuths(controller, setAuthReqBuilder.build(), rpcCallback);
}
return rpcCallback.get();
}
};
Map<byte[], VisibilityLabelsResponse> result = ht.coprocessorService(
VisibilityLabelsService.class, HConstants.EMPTY_BYTE_ARRAY, HConstants.EMPTY_BYTE_ARRAY,
callable);
return result.values().iterator().next(); // There will be exactly one region for labels
// table and so one entry in result Map.
} finally {
if (ht != null) {
ht.close();
}
}
}
}

View File

@ -0,0 +1,43 @@
/**
* 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.hadoop.hbase.security.visibility;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hbase.NamespaceDescriptor;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.util.Bytes;
@InterfaceAudience.Private
public final class VisibilityConstants {
/**
* The string that is used as key in setting the Operation attributes for visibility labels
*/
public static final String VISIBILITY_LABELS_ATTR_KEY = "VISIBILITY";
/** Internal storage table for visibility labels */
public static final TableName LABELS_TABLE_NAME = TableName.valueOf(
NamespaceDescriptor.SYSTEM_NAMESPACE_NAME_STR, "labels");
/** Family for the internal storage table for visibility labels */
public static final byte[] LABELS_TABLE_FAMILY = Bytes.toBytes("f");
/** Qualifier for the internal storage table for visibility labels */
public static final byte[] LABEL_QUALIFIER = new byte[1];
}

View File

@ -0,0 +1,66 @@
/*
* 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.hadoop.hbase.security.visibility;
import org.apache.hadoop.classification.InterfaceAudience;
/**
* A simple validator that validates the labels passed
*/
@InterfaceAudience.Private
public class VisibilityLabelsValidator {
// We follow Accumulo parity for valid visibility labels.
private static final boolean[] validAuthChars = new boolean[256];
static {
for (int i = 0; i < 256; i++) {
validAuthChars[i] = false;
}
for (int i = 'a'; i <= 'z'; i++) {
validAuthChars[i] = true;
}
for (int i = 'A'; i <= 'Z'; i++) {
validAuthChars[i] = true;
}
for (int i = '0'; i <= '9'; i++) {
validAuthChars[i] = true;
}
validAuthChars['_'] = true;
validAuthChars['-'] = true;
validAuthChars[':'] = true;
validAuthChars['.'] = true;
validAuthChars['/'] = true;
}
static final boolean isValidAuthChar(byte b) {
return validAuthChars[0xff & b];
}
static final boolean isValidLabel(byte[] label) {
for (int i = 0; i < label.length; i++) {
if (!isValidAuthChar(label[i])) {
return false;
}
}
return true;
}
}

View File

@ -24,6 +24,7 @@ import java.io.OutputStream;
import java.nio.ByteBuffer;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hbase.util.Pair;
import com.google.common.base.Preconditions;
@ -38,7 +39,6 @@ import com.google.common.base.Preconditions;
public class StreamUtils {
public static void writeRawVInt32(OutputStream output, int value) throws IOException {
assert value >= 0;
while (true) {
if ((value & ~0x7F) == 0) {
output.write(value);
@ -118,6 +118,57 @@ public class StreamUtils {
return result;
}
/**
* Reads a varInt value stored in an array.
*
* @param input
* Input array where the varInt is available
* @param offset
* Offset in the input array where varInt is available
* @return A pair of integers in which first value is the actual decoded varInt value and second
* value as number of bytes taken by this varInt for it's storage in the input array.
* @throws IOException
*/
public static Pair<Integer, Integer> readRawVarint32(byte[] input, int offset) throws IOException {
int newOffset = offset;
byte tmp = input[newOffset++];
if (tmp >= 0) {
return new Pair<Integer, Integer>((int) tmp, newOffset - offset);
}
int result = tmp & 0x7f;
tmp = input[newOffset++];
if (tmp >= 0) {
result |= tmp << 7;
} else {
result |= (tmp & 0x7f) << 7;
tmp = input[newOffset++];
if (tmp >= 0) {
result |= tmp << 14;
} else {
result |= (tmp & 0x7f) << 14;
tmp = input[newOffset++];
if (tmp >= 0) {
result |= tmp << 21;
} else {
result |= (tmp & 0x7f) << 21;
tmp = input[newOffset++];
result |= tmp << 28;
if (tmp < 0) {
// Discard upper 32 bits.
for (int i = 0; i < 5; i++) {
tmp = input[newOffset++];
if (tmp >= 0) {
return new Pair<Integer, Integer>(result, newOffset - offset);
}
}
throw new IOException("Malformed varint");
}
}
}
}
return new Pair<Integer, Integer>(result, newOffset - offset);
}
public static short toShort(byte hi, byte lo) {
short s = (short) (((hi & 0xFF) << 8) | (lo & 0xFF));
Preconditions.checkArgument(s >= 0);

View File

@ -29,6 +29,20 @@ import "Filter.proto";
import "Cell.proto";
import "Comparator.proto";
/**
* The protocol buffer version of Authorizations.
*/
message Authorizations {
repeated string label = 1;
}
/**
* The protocol buffer version of CellVisibility.
*/
message CellVisibility {
required string expression = 1;
}
/**
* Container for a list of column qualifier names of a family.
*/

View File

@ -0,0 +1,72 @@
/**
* 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.
*/
option java_package = "org.apache.hadoop.hbase.protobuf.generated";
option java_outer_classname = "VisibilityLabelsProtos";
option java_generic_services = true;
option java_generate_equals_and_hash = true;
option optimize_for = SPEED;
import "Client.proto";
message VisibilityLabelsRequest {
repeated VisibilityLabel visLabel = 1;
}
message VisibilityLabel {
required bytes label = 1;
optional uint32 ordinal = 2;
}
message VisibilityLabelsResponse {
repeated RegionActionResult result = 1;
}
message SetAuthsRequest {
required bytes user = 1;
repeated bytes auth = 2;
}
message UserAuthorizations {
required bytes user = 1;
repeated uint32 auth = 2;
}
message MultiUserAuthorizations {
repeated UserAuthorizations userAuths = 1;
}
message GetAuthsRequest {
required bytes user = 1;
}
message GetAuthsResponse {
required bytes user = 1;
repeated bytes auth = 2;
}
service VisibilityLabelsService {
rpc addLabels(VisibilityLabelsRequest)
returns (VisibilityLabelsResponse);
rpc setAuths(SetAuthsRequest)
returns (VisibilityLabelsResponse);
rpc clearAuths(SetAuthsRequest)
returns (VisibilityLabelsResponse);
rpc getAuths(GetAuthsRequest)
returns (GetAuthsResponse);
}

View File

@ -0,0 +1,87 @@
/**
* 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.hadoop.hbase.security.visibility;
import java.util.ArrayList;
import java.util.List;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.security.User;
/**
* This is the default implementation for ScanLabelGenerator. It will extract labels passed via
* Scan#authorizations and cross check against the global auths set for the user. The labels for which
* user is not authenticated will be dropped even if it is passed via Scan Authorizations.
*/
@InterfaceAudience.Private
public class DefaultScanLabelGenerator implements ScanLabelGenerator {
private static final Log LOG = LogFactory.getLog(DefaultScanLabelGenerator.class);
private Configuration conf;
private VisibilityLabelsManager labelsManager;
public DefaultScanLabelGenerator() {
this.labelsManager = VisibilityLabelsManager.get();
}
@Override
public void setConf(Configuration conf) {
this.conf = conf;
}
@Override
public Configuration getConf() {
return this.conf;
}
@Override
public List<String> getLabels(User user, Authorizations authorizations) {
if (authorizations != null) {
List<String> labels = authorizations.getLabels();
String userName = user.getName();
List<String> auths = this.labelsManager.getAuths(userName);
return dropLabelsNotInUserAuths(labels, auths, userName);
}
return null;
}
private List<String> dropLabelsNotInUserAuths(List<String> labels, List<String> auths,
String userName) {
List<String> droppedLabels = new ArrayList<String>();
List<String> passedLabels = new ArrayList<String>(labels.size());
for (String label : labels) {
if (auths.contains(label)) {
passedLabels.add(label);
} else {
droppedLabels.add(label);
}
}
if (!droppedLabels.isEmpty()) {
if (LOG.isDebugEnabled()) {
LOG.debug("Labels " + droppedLabels + " in Scan/Get visibility attributes dropped as user "
+ userName + " having no auth set for those.");
}
}
return passedLabels;
}
}

View File

@ -0,0 +1,184 @@
/**
* 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.hadoop.hbase.security.visibility;
import java.util.List;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hbase.security.visibility.expression.ExpressionNode;
import org.apache.hadoop.hbase.security.visibility.expression.LeafExpressionNode;
import org.apache.hadoop.hbase.security.visibility.expression.NonLeafExpressionNode;
import org.apache.hadoop.hbase.security.visibility.expression.Operator;
@InterfaceAudience.Private
public class ExpressionExpander {
public ExpressionNode expand(ExpressionNode src) {
if (!src.isSingleNode()) {
NonLeafExpressionNode nlExp = (NonLeafExpressionNode) src;
List<ExpressionNode> childExps = nlExp.getChildExps();
Operator outerOp = nlExp.getOperator();
if (isToBeExpanded(childExps)) {
// Any of the child exp is a non leaf exp with & or | operator
NonLeafExpressionNode newNode = new NonLeafExpressionNode(nlExp.getOperator());
for (ExpressionNode exp : childExps) {
if (exp.isSingleNode()) {
newNode.addChildExp(exp);
} else {
newNode.addChildExp(expand(exp));
}
}
nlExp = expandNonLeaf(newNode, outerOp);
}
return nlExp;
}
if (src instanceof NonLeafExpressionNode
&& ((NonLeafExpressionNode) src).getOperator() == Operator.NOT) {
// Negate the exp
return negate((NonLeafExpressionNode) src);
}
return src;
}
private ExpressionNode negate(NonLeafExpressionNode nlExp) {
ExpressionNode notChild = nlExp.getChildExps().get(0);
if (notChild instanceof LeafExpressionNode) {
return nlExp;
}
NonLeafExpressionNode nlNotChild = (NonLeafExpressionNode) notChild;
if (nlNotChild.getOperator() == Operator.NOT) {
// negate the negate
return nlNotChild.getChildExps().get(0);
}
Operator negateOp = nlNotChild.getOperator() == Operator.AND ? Operator.OR : Operator.AND;
NonLeafExpressionNode newNode = new NonLeafExpressionNode(negateOp);
for (ExpressionNode expNode : nlNotChild.getChildExps()) {
NonLeafExpressionNode negateNode = new NonLeafExpressionNode(Operator.NOT);
negateNode.addChildExp(expNode.deepClone());
newNode.addChildExp(expand(negateNode));
}
return newNode;
}
private boolean isToBeExpanded(List<ExpressionNode> childExps) {
for (ExpressionNode exp : childExps) {
if (!exp.isSingleNode()) {
return true;
}
}
return false;
}
private NonLeafExpressionNode expandNonLeaf(NonLeafExpressionNode newNode, Operator outerOp) {
// Now go for the merge or expansion across brackets
List<ExpressionNode> newChildExps = newNode.getChildExps();
assert newChildExps.size() == 2;
ExpressionNode leftChild = newChildExps.get(0);
ExpressionNode rightChild = newChildExps.get(1);
if (rightChild.isSingleNode()) {
// Merge the single right node into the left side
assert leftChild instanceof NonLeafExpressionNode;
newNode = mergeChildNodes(newNode, outerOp, rightChild, (NonLeafExpressionNode) leftChild);
} else if (leftChild.isSingleNode()) {
// Merge the single left node into the right side
assert rightChild instanceof NonLeafExpressionNode;
newNode = mergeChildNodes(newNode, outerOp, leftChild, (NonLeafExpressionNode) rightChild);
} else {
// Both the child exp nodes are non single.
NonLeafExpressionNode leftChildNLE = (NonLeafExpressionNode) leftChild;
NonLeafExpressionNode rightChildNLE = (NonLeafExpressionNode) rightChild;
if (outerOp == leftChildNLE.getOperator() && outerOp == rightChildNLE.getOperator()) {
// Merge
NonLeafExpressionNode leftChildNLEClone = leftChildNLE.deepClone();
leftChildNLEClone.addChildExps(rightChildNLE.getChildExps());
newNode = leftChildNLEClone;
} else {
// (a | b) & (c & d) ...
if (outerOp == Operator.OR) {
// (a | b) | (c & d)
if (leftChildNLE.getOperator() == Operator.OR
&& rightChildNLE.getOperator() == Operator.AND) {
leftChildNLE.addChildExp(rightChildNLE);
newNode = leftChildNLE;
} else if (leftChildNLE.getOperator() == Operator.AND
&& rightChildNLE.getOperator() == Operator.OR) {
// (a & b) | (c | d)
rightChildNLE.addChildExp(leftChildNLE);
newNode = rightChildNLE;
}
// (a & b) | (c & d)
// This case no need to do any thing
} else {
// outer op is &
// (a | b) & (c & d) => (a & c & d) | (b & c & d)
if (leftChildNLE.getOperator() == Operator.OR
&& rightChildNLE.getOperator() == Operator.AND) {
newNode = new NonLeafExpressionNode(Operator.OR);
for (ExpressionNode exp : leftChildNLE.getChildExps()) {
NonLeafExpressionNode rightChildNLEClone = rightChildNLE.deepClone();
rightChildNLEClone.addChildExp(exp);
newNode.addChildExp(rightChildNLEClone);
}
} else if (leftChildNLE.getOperator() == Operator.AND
&& rightChildNLE.getOperator() == Operator.OR) {
// (a & b) & (c | d) => (a & b & c) | (a & b & d)
newNode = new NonLeafExpressionNode(Operator.OR);
for (ExpressionNode exp : rightChildNLE.getChildExps()) {
NonLeafExpressionNode leftChildNLEClone = leftChildNLE.deepClone();
leftChildNLEClone.addChildExp(exp);
newNode.addChildExp(leftChildNLEClone);
}
} else {
// (a | b) & (c | d) => (a & c) | (a & d) | (b & c) | (b & d)
newNode = new NonLeafExpressionNode(Operator.OR);
for (ExpressionNode leftExp : leftChildNLE.getChildExps()) {
for (ExpressionNode rightExp : rightChildNLE.getChildExps()) {
NonLeafExpressionNode newChild = new NonLeafExpressionNode(Operator.AND);
newChild.addChildExp(leftExp.deepClone());
newChild.addChildExp(rightExp.deepClone());
newNode.addChildExp(newChild);
}
}
}
}
}
}
return newNode;
}
private NonLeafExpressionNode mergeChildNodes(NonLeafExpressionNode newOuterNode,
Operator outerOp, ExpressionNode lChild, NonLeafExpressionNode nlChild) {
// Merge the single right/left node into the other side
if (nlChild.getOperator() == outerOp) {
NonLeafExpressionNode leftChildNLEClone = nlChild.deepClone();
leftChildNLEClone.addChildExp(lChild);
newOuterNode = leftChildNLEClone;
} else if (outerOp == Operator.AND) {
assert nlChild.getOperator() == Operator.OR;
// outerOp is & here. We need to expand the node here
// (a | b) & c -> (a & c) | (b & c)
// OR
// c & (a | b) -> (c & a) | (c & b)
newOuterNode = new NonLeafExpressionNode(Operator.OR);
for (ExpressionNode exp : nlChild.getChildExps()) {
newOuterNode.addChildExp(new NonLeafExpressionNode(Operator.AND, exp, lChild));
}
}
return newOuterNode;
}
}

View File

@ -0,0 +1,273 @@
/**
* 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.hadoop.hbase.security.visibility;
import java.util.Stack;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hbase.security.visibility.expression.ExpressionNode;
import org.apache.hadoop.hbase.security.visibility.expression.LeafExpressionNode;
import org.apache.hadoop.hbase.security.visibility.expression.NonLeafExpressionNode;
import org.apache.hadoop.hbase.security.visibility.expression.Operator;
import org.apache.hadoop.hbase.util.Bytes;
@InterfaceAudience.Private
public class ExpressionParser {
private static final char CLOSE_PARAN = ')';
private static final char OPEN_PARAN = '(';
private static final char OR = '|';
private static final char AND = '&';
private static final char NOT = '!';
private static final char SPACE = ' ';
public ExpressionNode parse(String expS) throws ParseException {
expS = expS.trim();
Stack<ExpressionNode> expStack = new Stack<ExpressionNode>();
int index = 0;
int endPos = expS.length();
byte[] exp = Bytes.toBytes(expS);
while (index < endPos) {
byte b = exp[index];
switch (b) {
case OPEN_PARAN:
processOpenParan(expStack, expS, index);
index = skipSpaces(exp, index);
break;
case CLOSE_PARAN:
processCloseParan(expStack, expS, index);
index = skipSpaces(exp, index);
break;
case AND:
case OR:
processANDorOROp(getOperator(b), expStack, expS, index);
index = skipSpaces(exp, index);
break;
case NOT:
processNOTOp(expStack, expS, index);
break;
default:
int labelOffset = index;
do {
if (!VisibilityLabelsValidator.isValidAuthChar(exp[index])) {
throw new ParseException("Error parsing expression " + expS + " at column : "
+ index);
}
index++;
} while (index < endPos && !isEndOfLabel(exp[index]));
String leafExp = new String(exp, labelOffset, index - labelOffset).trim();
if (leafExp.isEmpty()) {
throw new ParseException("Error parsing expression " + expS + " at column : " + index);
}
processLabelExpNode(new LeafExpressionNode(leafExp), expStack, expS, index);
// We already crossed the label node index. So need to reduce 1 here.
index--;
index = skipSpaces(exp, index);
}
index++;
}
if (expStack.size() != 1) {
throw new ParseException("Error parsing expression " + expS);
}
ExpressionNode top = expStack.pop();
if (top == LeafExpressionNode.OPEN_PARAN_NODE) {
throw new ParseException("Error parsing expression " + expS);
}
if (top instanceof NonLeafExpressionNode) {
NonLeafExpressionNode nlTop = (NonLeafExpressionNode) top;
if (nlTop.getOperator() == Operator.NOT) {
if (nlTop.getChildExps().size() != 1) {
throw new ParseException("Error parsing expression " + expS);
}
} else if (nlTop.getChildExps().size() != 2) {
throw new ParseException("Error parsing expression " + expS);
}
}
return top;
}
private int skipSpaces(byte[] exp, int index) {
while (index < exp.length -1 && exp[index+1] == SPACE) {
index++;
}
return index;
}
private void processCloseParan(Stack<ExpressionNode> expStack, String expS, int index)
throws ParseException {
if (expStack.size() < 2) {
// When ) comes we expect atleast a ( node and another leaf/non leaf node
// in stack.
throw new ParseException();
} else {
ExpressionNode top = expStack.pop();
ExpressionNode secondTop = expStack.pop();
// The second top must be a ( node and top should not be a ). Top can be
// any thing else
if (top == LeafExpressionNode.OPEN_PARAN_NODE
|| secondTop != LeafExpressionNode.OPEN_PARAN_NODE) {
throw new ParseException("Error parsing expression " + expS + " at column : " + index);
}
// a&(b|) is not valid.
// The top can be a ! node but with exactly child nodes. !).. is invalid
// Other NonLeafExpressionNode , then there should be exactly 2 child.
// (a&) is not valid.
if (top instanceof NonLeafExpressionNode) {
NonLeafExpressionNode nlTop = (NonLeafExpressionNode) top;
if ((nlTop.getOperator() == Operator.NOT && nlTop.getChildExps().size() != 1)
|| (nlTop.getOperator() != Operator.NOT && nlTop.getChildExps().size() != 2)) {
throw new ParseException("Error parsing expression " + expS + " at column : " + index);
}
}
// When (a|b)&(c|d) comes while processing the second ) there will be
// already (a|b)& node
// avail in the stack. The top will be c|d node. We need to take it out
// and combine as one
// node.
if (!expStack.isEmpty()) {
ExpressionNode thirdTop = expStack.peek();
if (thirdTop instanceof NonLeafExpressionNode) {
NonLeafExpressionNode nlThirdTop = (NonLeafExpressionNode) expStack.pop();
nlThirdTop.addChildExp(top);
if (nlThirdTop.getOperator() == Operator.NOT) {
// It is a NOT node. So there may be a NonLeafExpressionNode below
// it to which the
// completed NOT can be added now.
if (!expStack.isEmpty()) {
ExpressionNode fourthTop = expStack.peek();
if (fourthTop instanceof NonLeafExpressionNode) {
// Its Operator will be OR or AND
NonLeafExpressionNode nlFourthTop = (NonLeafExpressionNode) fourthTop;
assert nlFourthTop.getOperator() != Operator.NOT;
// Also for sure its number of children will be 1
assert nlFourthTop.getChildExps().size() == 1;
nlFourthTop.addChildExp(nlThirdTop);
return;// This case no need to add back the nlThirdTop.
}
}
}
top = nlThirdTop;
}
}
expStack.push(top);
}
}
private void processOpenParan(Stack<ExpressionNode> expStack, String expS, int index)
throws ParseException {
if (!expStack.isEmpty()) {
ExpressionNode top = expStack.peek();
// Top can not be a Label Node. a(.. is not valid. but ((a.. is fine.
if (top instanceof LeafExpressionNode && top != LeafExpressionNode.OPEN_PARAN_NODE) {
throw new ParseException("Error parsing expression " + expS + " at column : " + index);
} else if (top instanceof NonLeafExpressionNode) {
// Top is non leaf.
// It can be ! node but with out any child nodes. !a(.. is invalid
// Other NonLeafExpressionNode , then there should be exactly 1 child.
// a&b( is not valid.
// a&( is valid though. Also !( is valid
NonLeafExpressionNode nlTop = (NonLeafExpressionNode) top;
if ((nlTop.getOperator() == Operator.NOT && nlTop.getChildExps().size() != 0)
|| (nlTop.getOperator() != Operator.NOT && nlTop.getChildExps().size() != 1)) {
throw new ParseException("Error parsing expression " + expS + " at column : " + index);
}
}
}
expStack.push(LeafExpressionNode.OPEN_PARAN_NODE);
}
private void processLabelExpNode(LeafExpressionNode node, Stack<ExpressionNode> expStack,
String expS, int index) throws ParseException {
if (expStack.isEmpty()) {
expStack.push(node);
} else {
ExpressionNode top = expStack.peek();
if (top == LeafExpressionNode.OPEN_PARAN_NODE) {
expStack.push(node);
} else if (top instanceof NonLeafExpressionNode) {
NonLeafExpressionNode nlTop = (NonLeafExpressionNode) expStack.pop();
nlTop.addChildExp(node);
if (nlTop.getOperator() == Operator.NOT && !expStack.isEmpty()) {
ExpressionNode secondTop = expStack.peek();
if (secondTop == LeafExpressionNode.OPEN_PARAN_NODE) {
expStack.push(nlTop);
} else if (secondTop instanceof NonLeafExpressionNode) {
((NonLeafExpressionNode) secondTop).addChildExp(nlTop);
}
} else {
expStack.push(nlTop);
}
} else {
throw new ParseException("Error parsing expression " + expS + " at column : " + index);
}
}
}
private void processANDorOROp(Operator op, Stack<ExpressionNode> expStack, String expS, int index)
throws ParseException {
if (expStack.isEmpty()) {
throw new ParseException("Error parsing expression " + expS + " at column : " + index);
}
ExpressionNode top = expStack.pop();
if (top.isSingleNode()) {
if (top == LeafExpressionNode.OPEN_PARAN_NODE) {
throw new ParseException("Error parsing expression " + expS + " at column : " + index);
}
expStack.push(new NonLeafExpressionNode(op, top));
} else {
NonLeafExpressionNode nlTop = (NonLeafExpressionNode) top;
if (nlTop.getChildExps().size() != 2) {
throw new ParseException("Error parsing expression " + expS + " at column : " + index);
}
expStack.push(new NonLeafExpressionNode(op, nlTop));
}
}
private void processNOTOp(Stack<ExpressionNode> expStack, String expS, int index)
throws ParseException {
// When ! comes, the stack can be empty or top ( or top can be some exp like
// a&
// !!.., a!, a&b!, !a! are invalid
if (!expStack.isEmpty()) {
ExpressionNode top = expStack.peek();
if (top.isSingleNode() && top != LeafExpressionNode.OPEN_PARAN_NODE) {
throw new ParseException("Error parsing expression " + expS + " at column : " + index);
}
if (!top.isSingleNode() && ((NonLeafExpressionNode) top).getChildExps().size() != 1) {
throw new ParseException("Error parsing expression " + expS + " at column : " + index);
}
}
expStack.push(new NonLeafExpressionNode(Operator.NOT));
}
private static boolean isEndOfLabel(byte b) {
return (b == OPEN_PARAN || b == CLOSE_PARAN || b == OR || b == AND || b == NOT || b == SPACE);
}
private static Operator getOperator(byte op) {
switch (op) {
case AND:
return Operator.AND;
case OR:
return Operator.OR;
case NOT:
return Operator.NOT;
}
return null;
}
}

View File

@ -0,0 +1,43 @@
/**
* 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.hadoop.hbase.security.visibility;
import org.apache.hadoop.classification.InterfaceAudience;
@InterfaceAudience.Private
public class ParseException extends Exception {
private static final long serialVersionUID = 1725986524206989173L;
public ParseException() {
}
public ParseException(String msg) {
super(msg);
}
public ParseException(Throwable t) {
super(t);
}
public ParseException(String msg, Throwable t) {
super(msg, t);
}
}

View File

@ -0,0 +1,43 @@
/**
* 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.hadoop.hbase.security.visibility;
import java.util.List;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.classification.InterfaceStability;
import org.apache.hadoop.conf.Configurable;
import org.apache.hadoop.hbase.security.User;
/**
* This would be the interface which would be used add labels to the RPC context
* and this would be stored against the UGI.
*
*/
@InterfaceAudience.Public
@InterfaceStability.Evolving
public interface ScanLabelGenerator extends Configurable {
/**
* Helps to get a list of lables associated with an UGI
* @param user
* @param authorizations
* @return The labels
*/
public List<String> getLabels(User user, Authorizations authorizations);
}

View File

@ -0,0 +1,52 @@
/**
* 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.hadoop.hbase.security.visibility;
import java.util.List;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.security.User;
/**
* This is a simple implementation for ScanLabelGenerator. It will just extract labels passed via
* Scan#Authorizations.
*/
@InterfaceAudience.Private
public class SimpleScanLabelGenerator implements ScanLabelGenerator {
private Configuration conf;
@Override
public void setConf(Configuration conf) {
this.conf = conf;
}
@Override
public Configuration getConf() {
return this.conf;
}
@Override
public List<String> getLabels(User user, Authorizations authorizations) {
if (authorizations != null) {
return authorizations.getLabels();
}
return null;
}
}

View File

@ -0,0 +1,84 @@
/**
* 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.hadoop.hbase.security.visibility;
import java.io.IOException;
import java.util.BitSet;
import java.util.Iterator;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellUtil;
import org.apache.hadoop.hbase.Tag;
import org.apache.hadoop.hbase.filter.FilterBase;
import org.apache.hadoop.hbase.io.util.StreamUtils;
import org.apache.hadoop.hbase.util.Pair;
/**
* This Filter checks the visibility expression with each KV against visibility labels associated
* with the scan. Based on the check the KV is included in the scan result or gets filtered out.
*/
@InterfaceAudience.Private
class VisibilityLabelFilter extends FilterBase {
private BitSet authLabels;
public VisibilityLabelFilter(BitSet authLabels) {
this.authLabels = authLabels;
}
@Override
public ReturnCode filterKeyValue(Cell cell) throws IOException {
Iterator<Tag> tagsItr = CellUtil.tagsIterator(cell.getTagsArray(), cell.getTagsOffset(),
cell.getTagsLength());
while (tagsItr.hasNext()) {
boolean includeKV = true;
Tag tag = tagsItr.next();
if (tag.getType() == VisibilityUtils.VISIBILITY_TAG_TYPE) {
int offset = tag.getTagOffset();
int endOffset = offset + tag.getTagLength();
while (offset < endOffset) {
Pair<Integer, Integer> result = StreamUtils.readRawVarint32(tag.getBuffer(), offset);
int currLabelOrdinal = result.getFirst();
if (currLabelOrdinal < 0) {
// check for the absence of this label in the Scan Auth labels
// ie. to check BitSet corresponding bit is 0
int temp = -currLabelOrdinal;
if (this.authLabels.get(temp)) {
includeKV = false;
break;
}
} else {
if (!this.authLabels.get(currLabelOrdinal)) {
includeKV = false;
break;
}
}
offset += result.getSecond();
}
if (includeKV) {
// We got one visibility expression getting evaluated to true. Good to include this KV in
// the result then.
return ReturnCode.INCLUDE;
}
return ReturnCode.SKIP;
}
}
return ReturnCode.INCLUDE;
}
}

View File

@ -0,0 +1,183 @@
/*
* 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.hadoop.hbase.security.visibility;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.MultiUserAuthorizations;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.UserAuthorizations;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabel;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
import org.apache.zookeeper.KeeperException;
/**
* Maintains the cache for visibility labels and also uses the zookeeper to update the labels in the
* system. The cache updation happens based on the data change event that happens on the zookeeper
* znode for labels table
*/
@InterfaceAudience.Private
public class VisibilityLabelsManager {
private static final Log LOG = LogFactory.getLog(VisibilityLabelsManager.class);
private static final List<String> EMPTY_LIST = new ArrayList<String>(0);
private static VisibilityLabelsManager instance;
private ZKVisibilityLabelWatcher zkVisibilityWatcher;
private Map<String, Integer> labels = new HashMap<String, Integer>();
private Map<Integer, String> ordinalVsLabels = new HashMap<Integer, String>();
private Map<String, Set<Integer>> userAuths = new HashMap<String, Set<Integer>>();
private ReentrantReadWriteLock lock = new ReentrantReadWriteLock();
private VisibilityLabelsManager(ZooKeeperWatcher watcher, Configuration conf) throws IOException {
zkVisibilityWatcher = new ZKVisibilityLabelWatcher(watcher, this, conf);
try {
zkVisibilityWatcher.start();
} catch (KeeperException ke) {
LOG.error("ZooKeeper initialization failed", ke);
throw new IOException(ke);
}
}
public synchronized static VisibilityLabelsManager get(ZooKeeperWatcher watcher,
Configuration conf) throws IOException {
if (instance == null) {
instance = new VisibilityLabelsManager(watcher, conf);
}
return instance;
}
public static VisibilityLabelsManager get() {
return instance;
}
public void refreshLabelsCache(byte[] data) throws IOException {
List<VisibilityLabel> visibilityLabels = null;
try {
visibilityLabels = VisibilityUtils.readLabelsFromZKData(data);
} catch (DeserializationException dse) {
throw new IOException(dse);
}
this.lock.writeLock().lock();
try {
for (VisibilityLabel visLabel : visibilityLabels) {
String label = Bytes.toString(visLabel.getLabel().toByteArray());
labels.put(label, visLabel.getOrdinal());
ordinalVsLabels.put(visLabel.getOrdinal(), label);
}
} finally {
this.lock.writeLock().unlock();
}
}
public void refreshUserAuthsCache(byte[] data) throws IOException {
MultiUserAuthorizations multiUserAuths = null;
try {
multiUserAuths = VisibilityUtils.readUserAuthsFromZKData(data);
} catch (DeserializationException dse) {
throw new IOException(dse);
}
this.lock.writeLock().lock();
try {
for (UserAuthorizations userAuths : multiUserAuths.getUserAuthsList()) {
String user = Bytes.toString(userAuths.getUser().toByteArray());
this.userAuths.put(user, new HashSet<Integer>(userAuths.getAuthList()));
}
} finally {
this.lock.writeLock().unlock();
}
}
/**
* @param label
* @return The ordinal for the label. The ordinal starts from 1. Returns 0 when the passed a non
* existing label.
*/
public int getLabelOrdinal(String label) {
Integer ordinal = null;
this.lock.readLock().lock();
try {
ordinal = labels.get(label);
} finally {
this.lock.readLock().unlock();
}
if (ordinal != null) {
return ordinal.intValue();
}
// 0 denotes not available
return 0;
}
public String getLabel(int ordinal) {
this.lock.readLock().lock();
try {
return this.ordinalVsLabels.get(ordinal);
} finally {
this.lock.readLock().unlock();
}
}
/**
* @return The total number of visibility labels.
*/
public int getLabelsCount(){
return this.labels.size();
}
/**
* @param user
* @return The labels that the given user is authorized for.
*/
public List<String> getAuths(String user) {
List<String> auths = EMPTY_LIST;
this.lock.readLock().lock();
try {
Set<Integer> authOrdinals = userAuths.get(user);
if (authOrdinals != null) {
auths = new ArrayList<String>(authOrdinals.size());
for (Integer authOrdinal : authOrdinals) {
auths.add(ordinalVsLabels.get(authOrdinal));
}
}
} finally {
this.lock.readLock().unlock();
}
return auths;
}
/**
* Writes the labels data to zookeeper node.
* @param data
* @param labelsOrUserAuths true for writing labels and false for user auths.
*/
public void writeToZookeeper(byte[] data, boolean labelsOrUserAuths) {
this.zkVisibilityWatcher.writeToZookeeper(data, labelsOrUserAuths);
}
}

View File

@ -0,0 +1,133 @@
/**
* 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.hadoop.hbase.security.visibility;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.exceptions.DeserializationException;
import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.MultiUserAuthorizations;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.UserAuthorizations;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabel;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsRequest;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.util.ReflectionUtils;
import com.google.protobuf.InvalidProtocolBufferException;
import com.google.protobuf.ZeroCopyLiteralByteString;
/**
* Utility method to support visibility
*/
@InterfaceAudience.Private
public class VisibilityUtils {
public static final String VISIBILITY_LABEL_GENERATOR_CLASS =
"hbase.regionserver.scan.visibility.label.generator.class";
public static final byte VISIBILITY_TAG_TYPE = (byte) 2;
public static final String SYSTEM_LABEL = "system";
/**
* Creates the labels data to be written to zookeeper.
* @param existingLabels
* @return Bytes form of labels and their ordinal details to be written to zookeeper.
*/
public static byte[] getDataToWriteToZooKeeper(Map<String, Integer> existingLabels) {
VisibilityLabelsRequest.Builder visReqBuilder = VisibilityLabelsRequest.newBuilder();
for (Entry<String, Integer> entry : existingLabels.entrySet()) {
VisibilityLabel.Builder visLabBuilder = VisibilityLabel.newBuilder();
visLabBuilder.setLabel(ZeroCopyLiteralByteString.wrap(Bytes.toBytes(entry.getKey())));
visLabBuilder.setOrdinal(entry.getValue());
visReqBuilder.addVisLabel(visLabBuilder.build());
}
return ProtobufUtil.prependPBMagic(visReqBuilder.build().toByteArray());
}
/**
* Creates the user auth data to be written to zookeeper.
* @param userAuths
* @return Bytes form of user auths details to be written to zookeeper.
*/
public static byte[] getUserAuthsDataToWriteToZooKeeper(Map<String, List<Integer>> userAuths) {
MultiUserAuthorizations.Builder builder = MultiUserAuthorizations.newBuilder();
for (Entry<String, List<Integer>> entry : userAuths.entrySet()) {
UserAuthorizations.Builder userAuthsBuilder = UserAuthorizations.newBuilder();
userAuthsBuilder.setUser(ZeroCopyLiteralByteString.wrap(Bytes.toBytes(entry.getKey())));
for (Integer label : entry.getValue()) {
userAuthsBuilder.addAuth(label);
}
builder.addUserAuths(userAuthsBuilder.build());
}
return ProtobufUtil.prependPBMagic(builder.build().toByteArray());
}
/**
* Reads back from the zookeeper. The data read here is of the form written by
* writeToZooKeeper(Map<byte[], Integer> entries).
*
* @param data
* @return Labels and their ordinal details
* @throws DeserializationException
*/
public static List<VisibilityLabel> readLabelsFromZKData(byte[] data)
throws DeserializationException {
if (ProtobufUtil.isPBMagicPrefix(data)) {
int pblen = ProtobufUtil.lengthOfPBMagic();
try {
VisibilityLabelsRequest request = VisibilityLabelsRequest.newBuilder()
.mergeFrom(data, pblen, data.length - pblen).build();
return request.getVisLabelList();
} catch (InvalidProtocolBufferException e) {
throw new DeserializationException(e);
}
}
return null;
}
/**
* Reads back User auth data written to zookeeper.
* @param data
* @return User auth details
* @throws DeserializationException
*/
public static MultiUserAuthorizations readUserAuthsFromZKData(byte[] data)
throws DeserializationException {
if (ProtobufUtil.isPBMagicPrefix(data)) {
int pblen = ProtobufUtil.lengthOfPBMagic();
try {
MultiUserAuthorizations multiUserAuths = MultiUserAuthorizations.newBuilder()
.mergeFrom(data, pblen, data.length - pblen).build();
return multiUserAuths;
} catch (InvalidProtocolBufferException e) {
throw new DeserializationException(e);
}
}
return null;
}
public static ScanLabelGenerator getScanLabelGenerator(Configuration conf) {
Class<? extends ScanLabelGenerator> scanLabelGeneratorKlass = conf
.getClass(VISIBILITY_LABEL_GENERATOR_CLASS, DefaultScanLabelGenerator.class,
ScanLabelGenerator.class);
return ReflectionUtils.newInstance(scanLabelGeneratorKlass, conf);
}
}

View File

@ -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.hadoop.hbase.security.visibility;
import java.io.IOException;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.hadoop.classification.InterfaceAudience;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.zookeeper.ZKUtil;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperListener;
import org.apache.hadoop.hbase.zookeeper.ZooKeeperWatcher;
import org.apache.zookeeper.KeeperException;
/**
* A zk watcher that watches the labels table znode. This would create a znode
* /hbase/visibility_labels and will have a serialized form of a set of labels in the system.
*/
@InterfaceAudience.Private
public class ZKVisibilityLabelWatcher extends ZooKeeperListener {
private static final Log LOG = LogFactory.getLog(ZKVisibilityLabelWatcher.class);
private static final String VISIBILITY_LABEL_ZK_PATH = "zookeeper.znode.visibility.label.parent";
private static final String DEFAULT_VISIBILITY_LABEL_NODE = "visibility/labels";
private static final String VISIBILITY_USER_AUTHS_ZK_PATH =
"zookeeper.znode.visibility.user.auths.parent";
private static final String DEFAULT_VISIBILITY_USER_AUTHS_NODE = "visibility/user_auths";
private VisibilityLabelsManager labelsManager;
private String labelZnode;
private String userAuthsZnode;
public ZKVisibilityLabelWatcher(ZooKeeperWatcher watcher, VisibilityLabelsManager labelsManager,
Configuration conf) {
super(watcher);
this.labelsManager = labelsManager;
String labelZnodeParent = conf.get(VISIBILITY_LABEL_ZK_PATH, DEFAULT_VISIBILITY_LABEL_NODE);
String userAuthsZnodeParent = conf.get(VISIBILITY_USER_AUTHS_ZK_PATH,
DEFAULT_VISIBILITY_USER_AUTHS_NODE);
this.labelZnode = ZKUtil.joinZNode(watcher.baseZNode, labelZnodeParent);
this.userAuthsZnode = ZKUtil.joinZNode(watcher.baseZNode, userAuthsZnodeParent);
}
public void start() throws KeeperException {
watcher.registerListener(this);
ZKUtil.watchAndCheckExists(watcher, labelZnode);
ZKUtil.watchAndCheckExists(watcher, userAuthsZnode);
}
private void refreshVisibilityLabelsCache(byte[] data) {
try {
this.labelsManager.refreshLabelsCache(data);
} catch (IOException ioe) {
LOG.error("Failed parsing data from labels table " + " from zk", ioe);
}
}
private void refreshUserAuthsCache(byte[] data) {
try {
this.labelsManager.refreshUserAuthsCache(data);
} catch (IOException ioe) {
LOG.error("Failed parsing data from labels table " + " from zk", ioe);
}
}
@Override
public void nodeCreated(String path) {
if (path.equals(labelZnode) || path.equals(userAuthsZnode)) {
try {
ZKUtil.watchAndCheckExists(watcher, path);
} catch (KeeperException ke) {
LOG.error("Error setting watcher on node " + path, ke);
// only option is to abort
watcher.abort("Zookeeper error obtaining label node children", ke);
}
}
}
@Override
public void nodeDeleted(String path) {
// There is no case of visibility labels path to get deleted.
}
@Override
public void nodeDataChanged(String path) {
if (path.equals(labelZnode) || path.equals(userAuthsZnode)) {
try {
watcher.sync(path);
byte[] data = ZKUtil.getDataAndWatch(watcher, path);
if (path.equals(labelZnode)) {
refreshVisibilityLabelsCache(data);
} else {
refreshUserAuthsCache(data);
}
} catch (KeeperException ke) {
LOG.error("Error reading data from zookeeper for node " + path, ke);
// only option is to abort
watcher.abort("Zookeeper error getting data for node " + path, ke);
}
}
}
@Override
public void nodeChildrenChanged(String path) {
// We are not dealing with child nodes under the label znode or userauths znode.
}
/**
* Write a labels mirror or user auths mirror into zookeeper
*
* @param data
* @param labelsOrUserAuths true for writing labels and false for user auths.
*/
public void writeToZookeeper(byte[] data, boolean labelsOrUserAuths) {
String znode = this.labelZnode;
if (!labelsOrUserAuths) {
znode = this.userAuthsZnode;
}
try {
ZKUtil.createWithParents(watcher, znode);
ZKUtil.updateExistingNodeData(watcher, znode, data, -1);
} catch (KeeperException e) {
LOG.error("Failed writing to " + znode, e);
watcher.abort("Failed writing node " + znode + " to zookeeper", e);
}
}
}

View File

@ -0,0 +1,27 @@
/**
* 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.hadoop.hbase.security.visibility.expression;
import org.apache.hadoop.classification.InterfaceAudience;
@InterfaceAudience.Private
public interface ExpressionNode {
boolean isSingleNode();
ExpressionNode deepClone();
}

View File

@ -0,0 +1,65 @@
/**
* 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.hadoop.hbase.security.visibility.expression;
import org.apache.hadoop.classification.InterfaceAudience;
@InterfaceAudience.Private
public class LeafExpressionNode implements ExpressionNode {
public static final LeafExpressionNode OPEN_PARAN_NODE = new LeafExpressionNode("(");
public static final LeafExpressionNode CLOSE_PARAN_NODE = new LeafExpressionNode(")");
private String identifier;
public LeafExpressionNode(String identifier) {
this.identifier = identifier;
}
public String getIdentifier() {
return this.identifier;
}
@Override
public int hashCode() {
return this.identifier.hashCode();
}
@Override
public boolean equals(Object obj) {
if (obj instanceof LeafExpressionNode) {
LeafExpressionNode that = (LeafExpressionNode) obj;
return this.identifier.equals(that.identifier);
}
return false;
}
@Override
public String toString() {
return this.identifier;
}
@Override
public boolean isSingleNode() {
return true;
}
public LeafExpressionNode deepClone() {
LeafExpressionNode clone = new LeafExpressionNode(this.identifier);
return clone;
}
}

View File

@ -0,0 +1,102 @@
/**
* 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.hadoop.hbase.security.visibility.expression;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.classification.InterfaceAudience;
@InterfaceAudience.Private
public class NonLeafExpressionNode implements ExpressionNode {
private Operator op;
private List<ExpressionNode> childExps = new ArrayList<ExpressionNode>(2);
public NonLeafExpressionNode() {
}
public NonLeafExpressionNode(Operator op) {
this.op = op;
}
public NonLeafExpressionNode(Operator op, List<ExpressionNode> exps) {
this.op = op;
if (op == Operator.NOT && exps.size() > 1) {
throw new IllegalArgumentException(Operator.NOT + " should be on 1 child expression");
}
this.childExps = exps;
}
public NonLeafExpressionNode(Operator op, ExpressionNode... exps) {
this.op = op;
List<ExpressionNode> expLst = new ArrayList<ExpressionNode>();
for (ExpressionNode exp : exps) {
expLst.add(exp);
}
this.childExps = expLst;
}
public Operator getOperator() {
return op;
}
public List<ExpressionNode> getChildExps() {
return childExps;
}
public void addChildExp(ExpressionNode exp) {
if (op == Operator.NOT && this.childExps.size() == 1) {
throw new IllegalStateException(Operator.NOT + " should be on 1 child expression");
}
this.childExps.add(exp);
}
public void addChildExps(List<ExpressionNode> exps) {
this.childExps.addAll(exps);
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("(");
if (this.op == Operator.NOT) {
sb.append(this.op);
}
for (int i = 0; i < this.childExps.size(); i++) {
sb.append(childExps.get(i));
if (i < this.childExps.size() - 1) {
sb.append(" " + this.op + " ");
}
}
sb.append(")");
return sb.toString();
}
@Override
public boolean isSingleNode() {
return this.op == Operator.NOT;
}
public NonLeafExpressionNode deepClone() {
NonLeafExpressionNode clone = new NonLeafExpressionNode(this.op);
for (ExpressionNode exp : this.childExps) {
clone.addChildExp(exp.deepClone());
}
return clone;
}
}

View File

@ -0,0 +1,32 @@
/**
* 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.hadoop.hbase.security.visibility.expression;
public enum Operator {
AND('&'), OR('|'), NOT('!');
private char rep;
private Operator(char rep) {
this.rep = rep;
}
public String toString() {
return String.valueOf(this.rep);
};
}

View File

@ -0,0 +1,393 @@
/**
* 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.hadoop.hbase.security.visibility;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.apache.hadoop.hbase.SmallTests;
import org.apache.hadoop.hbase.security.visibility.expression.ExpressionNode;
import org.apache.hadoop.hbase.security.visibility.expression.LeafExpressionNode;
import org.apache.hadoop.hbase.security.visibility.expression.NonLeafExpressionNode;
import org.apache.hadoop.hbase.security.visibility.expression.Operator;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@Category(SmallTests.class)
public class TestExpressionExpander {
@Test
public void testPositiveCases() throws Exception {
ExpressionExpander expander = new ExpressionExpander();
// (!a) -> (!a)
NonLeafExpressionNode exp1 = new NonLeafExpressionNode(Operator.NOT,
new LeafExpressionNode("a"));
ExpressionNode result = expander.expand(exp1);
assertTrue(result instanceof NonLeafExpressionNode);
NonLeafExpressionNode nlResult = (NonLeafExpressionNode) result;
assertEquals(Operator.NOT, nlResult.getOperator());
assertEquals("a", ((LeafExpressionNode) nlResult.getChildExps().get(0)).getIdentifier());
// (a | b) -> (a | b)
NonLeafExpressionNode exp2 = new NonLeafExpressionNode(Operator.OR,
new LeafExpressionNode("a"), new LeafExpressionNode("b"));
result = expander.expand(exp2);
assertTrue(result instanceof NonLeafExpressionNode);
nlResult = (NonLeafExpressionNode) result;
assertEquals(Operator.OR, nlResult.getOperator());
assertEquals(2, nlResult.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlResult.getChildExps().get(0)).getIdentifier());
assertEquals("b", ((LeafExpressionNode) nlResult.getChildExps().get(1)).getIdentifier());
// (a & b) -> (a & b)
NonLeafExpressionNode exp3 = new NonLeafExpressionNode(Operator.AND,
new LeafExpressionNode("a"), new LeafExpressionNode("b"));
result = expander.expand(exp3);
assertTrue(result instanceof NonLeafExpressionNode);
nlResult = (NonLeafExpressionNode) result;
assertEquals(Operator.AND, nlResult.getOperator());
assertEquals(2, nlResult.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlResult.getChildExps().get(0)).getIdentifier());
assertEquals("b", ((LeafExpressionNode) nlResult.getChildExps().get(1)).getIdentifier());
// ((a | b) | c) -> (a | b | c)
NonLeafExpressionNode exp4 = new NonLeafExpressionNode(Operator.OR, new NonLeafExpressionNode(
Operator.OR, new LeafExpressionNode("a"), new LeafExpressionNode("b")),
new LeafExpressionNode("c"));
result = expander.expand(exp4);
assertTrue(result instanceof NonLeafExpressionNode);
nlResult = (NonLeafExpressionNode) result;
assertEquals(Operator.OR, nlResult.getOperator());
assertEquals(3, nlResult.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlResult.getChildExps().get(0)).getIdentifier());
assertEquals("b", ((LeafExpressionNode) nlResult.getChildExps().get(1)).getIdentifier());
assertEquals("c", ((LeafExpressionNode) nlResult.getChildExps().get(2)).getIdentifier());
// ((a & b) & c) -> (a & b & c)
NonLeafExpressionNode exp5 = new NonLeafExpressionNode(Operator.AND, new NonLeafExpressionNode(
Operator.AND, new LeafExpressionNode("a"), new LeafExpressionNode("b")),
new LeafExpressionNode("c"));
result = expander.expand(exp5);
assertTrue(result instanceof NonLeafExpressionNode);
nlResult = (NonLeafExpressionNode) result;
assertEquals(Operator.AND, nlResult.getOperator());
assertEquals(3, nlResult.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlResult.getChildExps().get(0)).getIdentifier());
assertEquals("b", ((LeafExpressionNode) nlResult.getChildExps().get(1)).getIdentifier());
assertEquals("c", ((LeafExpressionNode) nlResult.getChildExps().get(2)).getIdentifier());
// (a | b) & c -> ((a & c) | (b & c))
NonLeafExpressionNode exp6 = new NonLeafExpressionNode(Operator.AND, new NonLeafExpressionNode(
Operator.OR, new LeafExpressionNode("a"), new LeafExpressionNode("b")),
new LeafExpressionNode("c"));
result = expander.expand(exp6);
assertTrue(result instanceof NonLeafExpressionNode);
nlResult = (NonLeafExpressionNode) result;
assertEquals(Operator.OR, nlResult.getOperator());
assertEquals(2, nlResult.getChildExps().size());
NonLeafExpressionNode temp = (NonLeafExpressionNode) nlResult.getChildExps().get(0);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("c", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(1);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("c", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
// (a & b) | c -> ((a & b) | c)
NonLeafExpressionNode exp7 = new NonLeafExpressionNode(Operator.OR, new NonLeafExpressionNode(
Operator.AND, new LeafExpressionNode("a"), new LeafExpressionNode("b")),
new LeafExpressionNode("c"));
result = expander.expand(exp7);
assertTrue(result instanceof NonLeafExpressionNode);
nlResult = (NonLeafExpressionNode) result;
assertEquals(Operator.OR, nlResult.getOperator());
assertEquals(2, nlResult.getChildExps().size());
assertEquals("c", ((LeafExpressionNode) nlResult.getChildExps().get(1)).getIdentifier());
nlResult = (NonLeafExpressionNode) nlResult.getChildExps().get(0);
assertEquals(Operator.AND, nlResult.getOperator());
assertEquals(2, nlResult.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlResult.getChildExps().get(0)).getIdentifier());
assertEquals("b", ((LeafExpressionNode) nlResult.getChildExps().get(1)).getIdentifier());
// ((a & b) | c) & d -> (((a & b) & d) | (c & d))
NonLeafExpressionNode exp8 = new NonLeafExpressionNode(Operator.AND);
exp8.addChildExp(new NonLeafExpressionNode(Operator.OR, new NonLeafExpressionNode(Operator.AND,
new LeafExpressionNode("a"), new LeafExpressionNode("b")), new LeafExpressionNode("c")));
exp8.addChildExp(new LeafExpressionNode("d"));
result = expander.expand(exp8);
assertTrue(result instanceof NonLeafExpressionNode);
nlResult = (NonLeafExpressionNode) result;
assertEquals(Operator.OR, nlResult.getOperator());
assertEquals(2, nlResult.getChildExps().size());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(1);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("c", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("d", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(0);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("d", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) temp.getChildExps().get(0);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("b", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
// (a | b) | (c | d) -> (a | b | c | d)
NonLeafExpressionNode exp9 = new NonLeafExpressionNode(Operator.OR);
exp9.addChildExp(new NonLeafExpressionNode(Operator.OR, new LeafExpressionNode("a"),
new LeafExpressionNode("b")));
exp9.addChildExp(new NonLeafExpressionNode(Operator.OR, new LeafExpressionNode("c"),
new LeafExpressionNode("d")));
result = expander.expand(exp9);
assertTrue(result instanceof NonLeafExpressionNode);
nlResult = (NonLeafExpressionNode) result;
assertEquals(Operator.OR, nlResult.getOperator());
assertEquals(4, nlResult.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlResult.getChildExps().get(0)).getIdentifier());
assertEquals("b", ((LeafExpressionNode) nlResult.getChildExps().get(1)).getIdentifier());
assertEquals("c", ((LeafExpressionNode) nlResult.getChildExps().get(2)).getIdentifier());
assertEquals("d", ((LeafExpressionNode) nlResult.getChildExps().get(3)).getIdentifier());
// (a & b) & (c & d) -> (a & b & c & d)
NonLeafExpressionNode exp10 = new NonLeafExpressionNode(Operator.AND);
exp10.addChildExp(new NonLeafExpressionNode(Operator.AND, new LeafExpressionNode("a"),
new LeafExpressionNode("b")));
exp10.addChildExp(new NonLeafExpressionNode(Operator.AND, new LeafExpressionNode("c"),
new LeafExpressionNode("d")));
result = expander.expand(exp10);
assertTrue(result instanceof NonLeafExpressionNode);
nlResult = (NonLeafExpressionNode) result;
assertEquals(Operator.AND, nlResult.getOperator());
assertEquals(4, nlResult.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlResult.getChildExps().get(0)).getIdentifier());
assertEquals("b", ((LeafExpressionNode) nlResult.getChildExps().get(1)).getIdentifier());
assertEquals("c", ((LeafExpressionNode) nlResult.getChildExps().get(2)).getIdentifier());
assertEquals("d", ((LeafExpressionNode) nlResult.getChildExps().get(3)).getIdentifier());
// (a | b) & (c | d) -> ((a & c) | (a & d) | (b & c) | (b & d))
NonLeafExpressionNode exp11 = new NonLeafExpressionNode(Operator.AND);
exp11.addChildExp(new NonLeafExpressionNode(Operator.OR, new LeafExpressionNode("a"),
new LeafExpressionNode("b")));
exp11.addChildExp(new NonLeafExpressionNode(Operator.OR, new LeafExpressionNode("c"),
new LeafExpressionNode("d")));
result = expander.expand(exp11);
assertTrue(result instanceof NonLeafExpressionNode);
nlResult = (NonLeafExpressionNode) result;
assertEquals(Operator.OR, nlResult.getOperator());
assertEquals(4, nlResult.getChildExps().size());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(0);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("c", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(1);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("d", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(2);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("c", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(3);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("d", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
// (((a | b) | c) | d) & e -> ((a & e) | (b & e) | (c & e) | (d & e))
NonLeafExpressionNode exp12 = new NonLeafExpressionNode(Operator.AND);
NonLeafExpressionNode tempExp1 = new NonLeafExpressionNode(Operator.OR, new LeafExpressionNode(
"a"), new LeafExpressionNode("b"));
NonLeafExpressionNode tempExp2 = new NonLeafExpressionNode(Operator.OR, tempExp1,
new LeafExpressionNode("c"));
NonLeafExpressionNode tempExp3 = new NonLeafExpressionNode(Operator.OR, tempExp2,
new LeafExpressionNode("d"));
exp12.addChildExp(tempExp3);
exp12.addChildExp(new LeafExpressionNode("e"));
result = expander.expand(exp12);
assertTrue(result instanceof NonLeafExpressionNode);
nlResult = (NonLeafExpressionNode) result;
assertEquals(Operator.OR, nlResult.getOperator());
assertEquals(4, nlResult.getChildExps().size());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(0);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("e", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(1);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("e", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(2);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("c", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("e", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(3);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("d", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("e", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
// (a | b | c) & d -> ((a & d) | (b & d) | (c & d))
NonLeafExpressionNode exp13 = new NonLeafExpressionNode(Operator.AND,
new NonLeafExpressionNode(Operator.OR, new LeafExpressionNode("a"), new LeafExpressionNode(
"b"), new LeafExpressionNode("c")), new LeafExpressionNode("d"));
result = expander.expand(exp13);
assertTrue(result instanceof NonLeafExpressionNode);
nlResult = (NonLeafExpressionNode) result;
assertEquals(Operator.OR, nlResult.getOperator());
assertEquals(3, nlResult.getChildExps().size());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(0);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("d", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(1);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("d", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(2);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("c", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("d", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
// ((a | b) & (c | d)) & (e | f) -> (((a & c) & e) | ((a & c) & f) | ((a & d) & e) | ((a & d) &
// f) | ((b & c) & e) | ((b & c) & f) | ((b & d) & e) | ((b & d) & f))
NonLeafExpressionNode exp15 = new NonLeafExpressionNode(Operator.AND);
NonLeafExpressionNode temp1 = new NonLeafExpressionNode(Operator.AND);
temp1.addChildExp(new NonLeafExpressionNode(Operator.OR, new LeafExpressionNode("a"),
new LeafExpressionNode("b")));
temp1.addChildExp(new NonLeafExpressionNode(Operator.OR, new LeafExpressionNode("c"),
new LeafExpressionNode("d")));
exp15.addChildExp(temp1);
exp15.addChildExp(new NonLeafExpressionNode(Operator.OR, new LeafExpressionNode("e"),
new LeafExpressionNode("f")));
result = expander.expand(exp15);
assertTrue(result instanceof NonLeafExpressionNode);
nlResult = (NonLeafExpressionNode) result;
assertEquals(Operator.OR, nlResult.getOperator());
assertEquals(8, nlResult.getChildExps().size());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(0);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("e", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) temp.getChildExps().get(0);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("c", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(1);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("f", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) temp.getChildExps().get(0);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("c", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(2);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("e", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) temp.getChildExps().get(0);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("d", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(3);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("f", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) temp.getChildExps().get(0);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("d", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(4);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("e", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) temp.getChildExps().get(0);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("c", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(5);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("f", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) temp.getChildExps().get(0);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("c", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(6);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("e", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) temp.getChildExps().get(0);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("d", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(7);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("f", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
temp = (NonLeafExpressionNode) temp.getChildExps().get(0);
assertEquals(Operator.AND, temp.getOperator());
assertEquals(2, temp.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
assertEquals("d", ((LeafExpressionNode) temp.getChildExps().get(1)).getIdentifier());
// !(a | b) -> ((!a) & (!b))
NonLeafExpressionNode exp16 = new NonLeafExpressionNode(Operator.NOT,
new NonLeafExpressionNode(Operator.OR, new LeafExpressionNode("a"), new LeafExpressionNode(
"b")));
result = expander.expand(exp16);
assertTrue(result instanceof NonLeafExpressionNode);
nlResult = (NonLeafExpressionNode) result;
assertEquals(Operator.AND, nlResult.getOperator());
assertEquals(2, nlResult.getChildExps().size());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(0);
assertEquals(Operator.NOT, temp.getOperator());
assertEquals("a", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
temp = (NonLeafExpressionNode) nlResult.getChildExps().get(1);
assertEquals(Operator.NOT, temp.getOperator());
assertEquals("b", ((LeafExpressionNode) temp.getChildExps().get(0)).getIdentifier());
}
}

View File

@ -0,0 +1,318 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.security.visibility;
import static org.junit.Assert.fail;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import org.apache.hadoop.hbase.SmallTests;
import org.apache.hadoop.hbase.security.visibility.expression.ExpressionNode;
import org.apache.hadoop.hbase.security.visibility.expression.LeafExpressionNode;
import org.apache.hadoop.hbase.security.visibility.expression.NonLeafExpressionNode;
import org.apache.hadoop.hbase.security.visibility.expression.Operator;
import org.junit.Test;
import org.junit.experimental.categories.Category;
@Category(SmallTests.class)
public class TestExpressionParser {
private ExpressionParser parser = new ExpressionParser();
@Test
public void testPositiveCases() throws Exception {
// abc -> (abc)
ExpressionNode node = parser.parse("abc");
assertTrue(node instanceof LeafExpressionNode);
assertEquals("abc", ((LeafExpressionNode) node).getIdentifier());
// a&b|c&d -> (((a & b) | c) & )
node = parser.parse("a&b|c&d");
assertTrue(node instanceof NonLeafExpressionNode);
NonLeafExpressionNode nlNode = (NonLeafExpressionNode) node;
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("d", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
assertTrue(nlNode.getChildExps().get(0) instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) nlNode.getChildExps().get(0);
assertEquals(Operator.OR, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("c", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
assertTrue(nlNode.getChildExps().get(0) instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) nlNode.getChildExps().get(0);
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
assertEquals("a", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
// (a) -> (a)
node = parser.parse("(a)");
assertTrue(node instanceof LeafExpressionNode);
assertEquals("a", ((LeafExpressionNode) node).getIdentifier());
// (a&b) -> (a & b)
node = parser.parse(" ( a & b )");
assertTrue(node instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) node;
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
assertEquals("b", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
// ((((a&b)))) -> (a & b)
node = parser.parse("((((a&b))))");
assertTrue(node instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) node;
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
assertEquals("b", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
// (a|b)&(cc|def) -> ((a | b) & (cc | def))
node = parser.parse("( a | b ) & (cc|def)");
assertTrue(node instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) node;
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertTrue(nlNode.getChildExps().get(0) instanceof NonLeafExpressionNode);
assertTrue(nlNode.getChildExps().get(1) instanceof NonLeafExpressionNode);
NonLeafExpressionNode nlNodeLeft = (NonLeafExpressionNode) nlNode.getChildExps().get(0);
NonLeafExpressionNode nlNodeRight = (NonLeafExpressionNode) nlNode.getChildExps().get(1);
assertEquals(Operator.OR, nlNodeLeft.getOperator());
assertEquals(2, nlNodeLeft.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlNodeLeft.getChildExps().get(0)).getIdentifier());
assertEquals("b", ((LeafExpressionNode) nlNodeLeft.getChildExps().get(1)).getIdentifier());
assertEquals(Operator.OR, nlNodeRight.getOperator());
assertEquals(2, nlNodeRight.getChildExps().size());
assertEquals("cc", ((LeafExpressionNode) nlNodeRight.getChildExps().get(0)).getIdentifier());
assertEquals("def", ((LeafExpressionNode) nlNodeRight.getChildExps().get(1)).getIdentifier());
// a&(cc|de) -> (a & (cc | de))
node = parser.parse("a&(cc|de)");
assertTrue(node instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) node;
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
assertTrue(nlNode.getChildExps().get(1) instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) nlNode.getChildExps().get(1);
assertEquals(Operator.OR, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("cc", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
assertEquals("de", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
// (a&b)|c -> ((a & b) | c)
node = parser.parse("(a&b)|c");
assertTrue(node instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) node;
assertEquals(Operator.OR, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("c", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
assertTrue(nlNode.getChildExps().get(0) instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) nlNode.getChildExps().get(0);
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
assertEquals("b", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
// (a&b&c)|d -> (((a & b) & c) | d)
node = parser.parse("(a&b&c)|d");
assertTrue(node instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) node;
assertEquals(Operator.OR, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("d", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
assertTrue(nlNode.getChildExps().get(0) instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) nlNode.getChildExps().get(0);
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("c", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
assertTrue(nlNode.getChildExps().get(0) instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) nlNode.getChildExps().get(0);
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
assertEquals("a", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
// a&(b|(c|d)) -> (a & (b | (c | d)))
node = parser.parse("a&(b|(c|d))");
assertTrue(node instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) node;
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
assertTrue(nlNode.getChildExps().get(1) instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) nlNode.getChildExps().get(1);
assertEquals(Operator.OR, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
assertTrue(nlNode.getChildExps().get(1) instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) nlNode.getChildExps().get(1);
assertEquals(Operator.OR, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("c", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
assertEquals("d", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
// (!a) -> (!a)
node = parser.parse("(!a)");
assertTrue(node instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) node;
assertEquals(Operator.NOT, nlNode.getOperator());
assertEquals("a", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
// a&(!b) -> (a & (!b))
node = parser.parse("a&(!b)");
assertTrue(node instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) node;
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
assertTrue(nlNode.getChildExps().get(1) instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) nlNode.getChildExps().get(1);
assertEquals(Operator.NOT, nlNode.getOperator());
assertEquals(1, nlNode.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
// !a&b -> ((!a) & b)
node = parser.parse("!a&b");
assertTrue(node instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) node;
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
assertTrue(nlNode.getChildExps().get(0) instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) nlNode.getChildExps().get(0);
assertEquals(Operator.NOT, nlNode.getOperator());
assertEquals(1, nlNode.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
// !a&(!b) -> ((!a) & (!b))
node = parser.parse("!a&(!b)");
assertTrue(node instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) node;
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertTrue(nlNode.getChildExps().get(0) instanceof NonLeafExpressionNode);
assertTrue(nlNode.getChildExps().get(1) instanceof NonLeafExpressionNode);
nlNodeLeft = (NonLeafExpressionNode) nlNode.getChildExps().get(0);
nlNodeRight = (NonLeafExpressionNode) nlNode.getChildExps().get(1);
assertEquals(Operator.NOT, nlNodeLeft.getOperator());
assertEquals(1, nlNodeLeft.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlNodeLeft.getChildExps().get(0)).getIdentifier());
assertEquals(Operator.NOT, nlNodeRight.getOperator());
assertEquals(1, nlNodeRight.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) nlNodeRight.getChildExps().get(0)).getIdentifier());
// !a&!b -> ((!a) & (!b))
node = parser.parse("!a&!b");
assertTrue(node instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) node;
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertTrue(nlNode.getChildExps().get(0) instanceof NonLeafExpressionNode);
assertTrue(nlNode.getChildExps().get(1) instanceof NonLeafExpressionNode);
nlNodeLeft = (NonLeafExpressionNode) nlNode.getChildExps().get(0);
nlNodeRight = (NonLeafExpressionNode) nlNode.getChildExps().get(1);
assertEquals(Operator.NOT, nlNodeLeft.getOperator());
assertEquals(1, nlNodeLeft.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlNodeLeft.getChildExps().get(0)).getIdentifier());
assertEquals(Operator.NOT, nlNodeRight.getOperator());
assertEquals(1, nlNodeRight.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) nlNodeRight.getChildExps().get(0)).getIdentifier());
// !(a&b) -> (!(a & b))
node = parser.parse("!(a&b)");
assertTrue(node instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) node;
assertEquals(Operator.NOT, nlNode.getOperator());
assertEquals(1, nlNode.getChildExps().size());
nlNode = (NonLeafExpressionNode) nlNode.getChildExps().get(0);
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
assertEquals("b", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
// a&!b -> (a & (!b))
node = parser.parse("a&!b");
assertTrue(node instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) node;
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertEquals("a", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
assertTrue(nlNode.getChildExps().get(1) instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) nlNode.getChildExps().get(1);
assertEquals(Operator.NOT, nlNode.getOperator());
assertEquals(1, nlNode.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
// !((a|b)&!(c&!b)) -> (!((a | b) & (!(c & (!b)))))
node = parser.parse("!((a | b) & !(c & !b))");
assertTrue(node instanceof NonLeafExpressionNode);
nlNode = (NonLeafExpressionNode) node;
assertEquals(Operator.NOT, nlNode.getOperator());
assertEquals(1, nlNode.getChildExps().size());
nlNode = (NonLeafExpressionNode) nlNode.getChildExps().get(0);
assertEquals(Operator.AND, nlNode.getOperator());
assertEquals(2, nlNode.getChildExps().size());
assertTrue(nlNode.getChildExps().get(0) instanceof NonLeafExpressionNode);
assertTrue(nlNode.getChildExps().get(1) instanceof NonLeafExpressionNode);
nlNodeLeft = (NonLeafExpressionNode) nlNode.getChildExps().get(0);
nlNodeRight = (NonLeafExpressionNode) nlNode.getChildExps().get(1);
assertEquals(Operator.OR, nlNodeLeft.getOperator());
assertEquals("a", ((LeafExpressionNode) nlNodeLeft.getChildExps().get(0)).getIdentifier());
assertEquals("b", ((LeafExpressionNode) nlNodeLeft.getChildExps().get(1)).getIdentifier());
assertEquals(Operator.NOT, nlNodeRight.getOperator());
assertEquals(1, nlNodeRight.getChildExps().size());
nlNodeRight = (NonLeafExpressionNode) nlNodeRight.getChildExps().get(0);
assertEquals(Operator.AND, nlNodeRight.getOperator());
assertEquals(2, nlNodeRight.getChildExps().size());
assertEquals("c", ((LeafExpressionNode) nlNodeRight.getChildExps().get(0)).getIdentifier());
assertTrue(nlNodeRight.getChildExps().get(1) instanceof NonLeafExpressionNode);
nlNodeRight = (NonLeafExpressionNode) nlNodeRight.getChildExps().get(1);
assertEquals(Operator.NOT, nlNodeRight.getOperator());
assertEquals(1, nlNodeRight.getChildExps().size());
assertEquals("b", ((LeafExpressionNode) nlNodeRight.getChildExps().get(0)).getIdentifier());
}
@Test
public void testNegativeCases() throws Exception {
executeNegativeCase("(");
executeNegativeCase(")");
executeNegativeCase("()");
executeNegativeCase("(a");
executeNegativeCase("a&");
executeNegativeCase("a&|b");
executeNegativeCase("!");
executeNegativeCase("a!");
executeNegativeCase("a!&");
executeNegativeCase("&");
executeNegativeCase("|");
executeNegativeCase("!(a|(b&c)&!b");
executeNegativeCase("!!a");
executeNegativeCase("( a & b ) | ( c & d e)");
executeNegativeCase("! a");
}
private void executeNegativeCase(String exp) {
try {
parser.parse(exp);
fail("Expected ParseException for expression " + exp);
} catch (ParseException e) {
}
}
}

View File

@ -0,0 +1,675 @@
/**
* 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.hadoop.hbase.security.visibility;
import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABELS_TABLE_FAMILY;
import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABELS_TABLE_NAME;
import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABEL_QUALIFIER;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.junit.Assert.fail;
import java.io.IOException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.Cell;
import org.apache.hadoop.hbase.CellScanner;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.MediumTests;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Append;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Increment;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.protobuf.generated.ClientProtos.RegionActionResult;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.GetAuthsResponse;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsResponse;
import org.apache.hadoop.hbase.regionserver.HRegion;
import org.apache.hadoop.hbase.regionserver.HRegionServer;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.util.Bytes;
import org.apache.hadoop.hbase.util.JVMClusterUtil.RegionServerThread;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.TestName;
import com.google.protobuf.ByteString;
/**
* Test class that tests the visibility labels
*/
@Category(MediumTests.class)
public class TestVisibilityLabels {
private static final String TOPSECRET = "topsecret";
private static final String PUBLIC = "public";
private static final String PRIVATE = "private";
private static final String CONFIDENTIAL = "confidential";
private static final String SECRET = "secret";
private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
private static final byte[] row1 = Bytes.toBytes("row1");
private static final byte[] row2 = Bytes.toBytes("row2");
private static final byte[] row3 = Bytes.toBytes("row3");
private static final byte[] row4 = Bytes.toBytes("row4");
private final static byte[] fam = Bytes.toBytes("info");
private final static byte[] qual = Bytes.toBytes("qual");
private final static byte[] value = Bytes.toBytes("value");
private static Configuration conf;
private volatile boolean killedRS = false;
@Rule
public final TestName TEST_NAME = new TestName();
private static User SUPERUSER;
@BeforeClass
public static void setupBeforeClass() throws Exception {
// setup configuration
conf = TEST_UTIL.getConfiguration();
conf.setInt("hfile.format.version", 3);
conf.set("hbase.coprocessor.master.classes", VisibilityController.class.getName());
conf.set("hbase.coprocessor.region.classes", VisibilityController.class.getName());
conf.setClass(VisibilityUtils.VISIBILITY_LABEL_GENERATOR_CLASS, SimpleScanLabelGenerator.class,
ScanLabelGenerator.class);
String currentUser = User.getCurrent().getName();
conf.set("hbase.superuser", "admin,"+currentUser);
TEST_UTIL.startMiniCluster(2);
SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
// Wait for the labels table to become available
TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000);
addLabels();
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
TEST_UTIL.shutdownMiniCluster();
}
@After
public void tearDown() throws Exception {
killedRS = false;
}
@Test
public void testSimpleVisibilityLabels() throws Exception {
TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
HTable table = createTableAndWriteDataWithLabels(tableName, SECRET + "|" + CONFIDENTIAL,
PRIVATE + "|" + CONFIDENTIAL);
try {
Scan s = new Scan();
s.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL, PRIVATE));
ResultScanner scanner = table.getScanner(s);
Result[] next = scanner.next(3);
assertTrue(next.length == 2);
CellScanner cellScanner = next[0].cellScanner();
cellScanner.advance();
Cell current = cellScanner.current();
assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
current.getRowLength(), row1, 0, row1.length));
cellScanner = next[1].cellScanner();
cellScanner.advance();
current = cellScanner.current();
assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
current.getRowLength(), row2, 0, row2.length));
} finally {
if (table != null) {
table.close();
}
}
}
@Test
public void testVisibilityLabelsWithComplexLabels() throws Exception {
TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
HTable table = createTableAndWriteDataWithLabels(tableName, "(" + SECRET + "|" + CONFIDENTIAL
+ ")" + "&" + "!" + TOPSECRET, "(" + PRIVATE + "&" + CONFIDENTIAL + "&" + SECRET + ")", "("
+ PRIVATE + "&" + CONFIDENTIAL + "&" + SECRET + ")", "(" + PRIVATE + "&" + CONFIDENTIAL
+ "&" + SECRET + ")");
try {
Scan s = new Scan();
s.setAuthorizations(new Authorizations(TOPSECRET, CONFIDENTIAL, PRIVATE, PUBLIC, SECRET));
ResultScanner scanner = table.getScanner(s);
Result[] next = scanner.next(4);
assertEquals(3, next.length);
CellScanner cellScanner = next[0].cellScanner();
cellScanner.advance();
Cell current = cellScanner.current();
assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
current.getRowLength(), row2, 0, row2.length));
cellScanner = next[1].cellScanner();
cellScanner.advance();
current = cellScanner.current();
assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
current.getRowLength(), row3, 0, row3.length));
cellScanner = next[2].cellScanner();
cellScanner.advance();
current = cellScanner.current();
assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
current.getRowLength(), row4, 0, row4.length));
} finally {
if (table != null) {
table.close();
}
}
}
@Test
public void testVisibilityLabelsThatDoesNotPassTheCriteria() throws Exception {
TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
HTable table = createTableAndWriteDataWithLabels(tableName, "(" + SECRET + "|" + CONFIDENTIAL
+ ")", PRIVATE);
try {
Scan s = new Scan();
s.setAuthorizations(new Authorizations(PUBLIC));
ResultScanner scanner = table.getScanner(s);
Result[] next = scanner.next(3);
assertTrue(next.length == 0);
} finally {
if (table != null) {
table.close();
}
}
}
@Test
public void testVisibilityLabelsInPutsThatDoesNotMatchAnyDefinedLabels() throws Exception {
TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
try {
createTableAndWriteDataWithLabels(tableName, "SAMPLE_LABEL", "TEST");
fail("Should have failed with failed sanity check exception");
} catch (Exception e) {
}
}
@Test
public void testVisibilityLabelsInScanThatDoesNotMatchAnyDefinedLabels() throws Exception {
TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
HTable table = createTableAndWriteDataWithLabels(tableName, "(" + SECRET + "|" + CONFIDENTIAL
+ ")", PRIVATE);
try {
Scan s = new Scan();
s.setAuthorizations(new Authorizations("SAMPLE"));
ResultScanner scanner = table.getScanner(s);
Result[] next = scanner.next(3);
assertTrue(next.length == 0);
} finally {
if (table != null) {
table.close();
}
}
}
@Test
public void testVisibilityLabelsWithGet() throws Exception {
TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
HTable table = createTableAndWriteDataWithLabels(tableName, SECRET + "&" + CONFIDENTIAL + "&!"
+ PRIVATE, SECRET + "&" + CONFIDENTIAL + "&" + PRIVATE);
try {
Get get = new Get(row1);
get.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL));
Result result = table.get(get);
assertTrue(!result.isEmpty());
Cell cell = result.getColumnLatestCell(fam, qual);
assertTrue(Bytes.equals(value, 0, value.length, cell.getValueArray(), cell.getValueOffset(),
cell.getValueLength()));
} finally {
if (table != null) {
table.close();
}
}
}
@Test
public void testVisibilityLabelsOnKillingOfRSContainingLabelsTable() throws Exception {
List<RegionServerThread> regionServerThreads = TEST_UTIL.getHBaseCluster()
.getRegionServerThreads();
int liveRS = 0;
for (RegionServerThread rsThreads : regionServerThreads) {
if (!rsThreads.getRegionServer().isAborted()) {
liveRS++;
}
}
if (liveRS == 1) {
TEST_UTIL.getHBaseCluster().startRegionServer();
}
Thread t1 = new Thread() {
public void run() {
List<RegionServerThread> regionServerThreads = TEST_UTIL.getHBaseCluster()
.getRegionServerThreads();
for (RegionServerThread rsThread : regionServerThreads) {
List<HRegion> onlineRegions = rsThread.getRegionServer().getOnlineRegions(
LABELS_TABLE_NAME);
if (onlineRegions.size() > 0) {
rsThread.getRegionServer().abort("Aborting ");
killedRS = true;
break;
}
}
}
};
t1.start();
final TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
Thread t = new Thread() {
public void run() {
try {
while (!killedRS) {
Thread.sleep(1);
}
createTableAndWriteDataWithLabels(tableName, "(" + SECRET + "|" + CONFIDENTIAL + ")",
PRIVATE);
} catch (Exception e) {
}
}
};
t.start();
regionServerThreads = TEST_UTIL.getHBaseCluster().getRegionServerThreads();
while (!killedRS) {
Thread.sleep(10);
}
regionServerThreads = TEST_UTIL.getHBaseCluster().getRegionServerThreads();
for (RegionServerThread rsThread : regionServerThreads) {
while (true) {
if (!rsThread.getRegionServer().isAborted()) {
List<HRegion> onlineRegions = rsThread.getRegionServer().getOnlineRegions(
LABELS_TABLE_NAME);
if (onlineRegions.size() > 0) {
break;
} else {
Thread.sleep(10);
}
} else {
break;
}
}
}
TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000);
t.join();
HTable table = null;
try {
table = new HTable(TEST_UTIL.getConfiguration(), tableName);
Scan s = new Scan();
s.setAuthorizations(new Authorizations(SECRET));
ResultScanner scanner = table.getScanner(s);
Result[] next = scanner.next(3);
assertTrue(next.length == 1);
} finally {
if (table != null) {
table.close();
}
}
}
@Test
public void testVisibilityLabelsOnRSRestart() throws Exception {
final TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
List<RegionServerThread> regionServerThreads = TEST_UTIL.getHBaseCluster()
.getRegionServerThreads();
for (RegionServerThread rsThread : regionServerThreads) {
rsThread.getRegionServer().abort("Aborting ");
}
// Start one new RS
RegionServerThread rs = TEST_UTIL.getHBaseCluster().startRegionServer();
HRegionServer regionServer = rs.getRegionServer();
while (!regionServer.isOnline()) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
}
HTable table = createTableAndWriteDataWithLabels(tableName, "(" + SECRET + "|" + CONFIDENTIAL
+ ")", PRIVATE);
try {
Scan s = new Scan();
s.setAuthorizations(new Authorizations(SECRET));
ResultScanner scanner = table.getScanner(s);
Result[] next = scanner.next(3);
assertTrue(next.length == 1);
} finally {
if (table != null) {
table.close();
}
}
}
@Test
public void testAddVisibilityLabelsOnRSRestart() throws Exception {
List<RegionServerThread> regionServerThreads = TEST_UTIL.getHBaseCluster()
.getRegionServerThreads();
for (RegionServerThread rsThread : regionServerThreads) {
rsThread.getRegionServer().abort("Aborting ");
}
// Start one new RS
RegionServerThread rs = TEST_UTIL.getHBaseCluster().startRegionServer();
HRegionServer regionServer = rs.getRegionServer();
while (!regionServer.isOnline()) {
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
}
String[] labels = { SECRET, CONFIDENTIAL, PRIVATE, "ABC", "XYZ" };
try {
VisibilityClient.addLabels(conf, labels);
} catch (Throwable t) {
throw new IOException(t);
}
// Scan the visibility label
Scan s = new Scan();
s.setAuthorizations(new Authorizations(VisibilityUtils.SYSTEM_LABEL));
HTable ht = new HTable(conf, LABELS_TABLE_NAME.getName());
int i = 0;
try {
ResultScanner scanner = ht.getScanner(s);
while (true) {
Result next = scanner.next();
if (next == null) {
break;
}
i++;
}
} finally {
if (ht != null) {
ht.close();
}
}
// One label is the "system" label.
Assert.assertEquals("The count should be 8", 8, i);
}
@Test
public void testVisibilityLabelsInGetThatDoesNotMatchAnyDefinedLabels() throws Exception {
TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
HTable table = createTableAndWriteDataWithLabels(tableName, "(" + SECRET + "|" + CONFIDENTIAL
+ ")", PRIVATE);
try {
Get get = new Get(row1);
get.setAuthorizations(new Authorizations("SAMPLE"));
Result result = table.get(get);
assertTrue(result.isEmpty());
} finally {
if (table != null) {
table.close();
}
}
}
@Test
public void testAddLabels() throws Throwable {
String[] labels = { "L1", SECRET, "L2", "invalid~", "L3" };
VisibilityLabelsResponse response = VisibilityClient.addLabels(conf, labels);
List<RegionActionResult> resultList = response.getResultList();
assertEquals(5, resultList.size());
assertTrue(resultList.get(0).getException().getValue().isEmpty());
assertEquals("org.apache.hadoop.hbase.security.visibility.LabelAlreadyExistsException",
resultList.get(1).getException().getName());
assertTrue(resultList.get(2).getException().getValue().isEmpty());
assertEquals("org.apache.hadoop.hbase.security.visibility.InvalidLabelException", resultList
.get(3).getException().getName());
assertTrue(resultList.get(4).getException().getValue().isEmpty());
}
@Test
public void testSetAndGetUserAuths() throws Throwable {
String[] auths = { SECRET, CONFIDENTIAL };
String user = "user1";
VisibilityClient.setAuths(conf, auths, user);
HTable ht = null;
try {
ht = new HTable(conf, LABELS_TABLE_NAME);
ResultScanner scanner = ht.getScanner(new Scan());
Result result = null;
while ((result = scanner.next()) != null) {
Cell label = result.getColumnLatestCell(LABELS_TABLE_FAMILY, LABEL_QUALIFIER);
Cell userAuth = result.getColumnLatestCell(LABELS_TABLE_FAMILY, user.getBytes());
if (Bytes.equals(SECRET.getBytes(), 0, SECRET.getBytes().length, label.getValueArray(),
label.getValueOffset(), label.getValueLength())
|| Bytes.equals(CONFIDENTIAL.getBytes(), 0, CONFIDENTIAL.getBytes().length,
label.getValueArray(), label.getValueOffset(), label.getValueLength())) {
assertNotNull(userAuth);
} else {
assertNull(userAuth);
}
}
} finally {
if (ht != null) {
ht.close();
}
}
GetAuthsResponse authsResponse = VisibilityClient.getAuths(conf, user);
List<String> authsList = new ArrayList<String>();
for (ByteString authBS : authsResponse.getAuthList()) {
authsList.add(Bytes.toString(authBS.toByteArray()));
}
assertEquals(2, authsList.size());
assertTrue(authsList.contains(SECRET));
assertTrue(authsList.contains(CONFIDENTIAL));
// Try doing setAuths once again and there should not be any duplicates
String[] auths1 = { SECRET, CONFIDENTIAL };
user = "user1";
VisibilityClient.setAuths(conf, auths1, user);
authsResponse = VisibilityClient.getAuths(conf, user);
authsList = new ArrayList<String>();
for (ByteString authBS : authsResponse.getAuthList()) {
authsList.add(Bytes.toString(authBS.toByteArray()));
}
assertEquals(2, authsList.size());
assertTrue(authsList.contains(SECRET));
assertTrue(authsList.contains(CONFIDENTIAL));
}
@Test
public void testClearUserAuths() throws Throwable {
String[] auths = { SECRET, CONFIDENTIAL, PRIVATE };
String user = "testUser";
VisibilityClient.setAuths(conf, auths, user);
// Removing the auths for SECRET and CONFIDENTIAL for the user.
// Passing a non existing auth also.
auths = new String[] { SECRET, PUBLIC, CONFIDENTIAL };
VisibilityLabelsResponse response = VisibilityClient.clearAuths(conf, auths, user);
List<RegionActionResult> resultList = response.getResultList();
assertEquals(3, resultList.size());
assertTrue(resultList.get(0).getException().getValue().isEmpty());
assertEquals("org.apache.hadoop.hbase.security.visibility.InvalidLabelException",
resultList.get(1).getException().getName());
assertTrue(resultList.get(2).getException().getValue().isEmpty());
HTable ht = null;
try {
ht = new HTable(conf, LABELS_TABLE_NAME);
ResultScanner scanner = ht.getScanner(new Scan());
Result result = null;
while ((result = scanner.next()) != null) {
Cell label = result.getColumnLatestCell(LABELS_TABLE_FAMILY, LABEL_QUALIFIER);
Cell userAuth = result.getColumnLatestCell(LABELS_TABLE_FAMILY, user.getBytes());
if (Bytes.equals(PRIVATE.getBytes(), 0, PRIVATE.getBytes().length, label.getValueArray(),
label.getValueOffset(), label.getValueLength())) {
assertNotNull(userAuth);
} else {
assertNull(userAuth);
}
}
} finally {
if (ht != null) {
ht.close();
}
}
GetAuthsResponse authsResponse = VisibilityClient.getAuths(conf, user);
List<String> authsList = new ArrayList<String>();
for (ByteString authBS : authsResponse.getAuthList()) {
authsList.add(Bytes.toString(authBS.toByteArray()));
}
assertEquals(1, authsList.size());
assertTrue(authsList.contains(PRIVATE));
}
@Test
public void testLablesWithCheckAndPut() throws Throwable {
TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
HTable table = null;
try {
table = TEST_UTIL.createTable(tableName, fam);
byte[] row1 = Bytes.toBytes("row1");
Put put = new Put(row1);
put.add(fam, qual, HConstants.LATEST_TIMESTAMP, value);
put.setCellVisibility(new CellVisibility(SECRET + " & " + CONFIDENTIAL));
table.checkAndPut(row1, fam, qual, null, put);
byte[] row2 = Bytes.toBytes("row2");
put = new Put(row2);
put.add(fam, qual, HConstants.LATEST_TIMESTAMP, value);
put.setCellVisibility(new CellVisibility(SECRET));
table.checkAndPut(row2, fam, qual, null, put);
Scan scan = new Scan();
scan.setAuthorizations(new Authorizations(SECRET));
ResultScanner scanner = table.getScanner(scan);
Result result = scanner.next();
assertTrue(!result.isEmpty());
assertTrue(Bytes.equals(row2, result.getRow()));
result = scanner.next();
assertNull(result);
} finally {
if (table != null) {
table.close();
}
}
}
@Test
public void testLablesWithIncrement() throws Throwable {
TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
HTable table = null;
try {
table = TEST_UTIL.createTable(tableName, fam);
byte[] row1 = Bytes.toBytes("row1");
byte[] val = Bytes.toBytes(1L);
Put put = new Put(row1);
put.add(fam, qual, HConstants.LATEST_TIMESTAMP, val);
put.setCellVisibility(new CellVisibility(SECRET + " & " + CONFIDENTIAL));
table.put(put);
Get get = new Get(row1);
get.setAuthorizations(new Authorizations(SECRET));
Result result = table.get(get);
assertTrue(result.isEmpty());
table.incrementColumnValue(row1, fam, qual, 2L);
result = table.get(get);
assertTrue(result.isEmpty());
Increment increment = new Increment(row1);
increment.addColumn(fam, qual, 2L);
increment.setCellVisibility(new CellVisibility(SECRET));
table.increment(increment);
result = table.get(get);
assertTrue(!result.isEmpty());
} finally {
if (table != null) {
table.close();
}
}
}
@Test
public void testLablesWithAppend() throws Throwable {
TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
HTable table = null;
try {
table = TEST_UTIL.createTable(tableName, fam);
byte[] row1 = Bytes.toBytes("row1");
byte[] val = Bytes.toBytes("a");
Put put = new Put(row1);
put.add(fam, qual, HConstants.LATEST_TIMESTAMP, val);
put.setCellVisibility(new CellVisibility(SECRET + " & " + CONFIDENTIAL));
table.put(put);
Get get = new Get(row1);
get.setAuthorizations(new Authorizations(SECRET));
Result result = table.get(get);
assertTrue(result.isEmpty());
Append append = new Append(row1);
append.add(fam, qual, Bytes.toBytes("b"));
table.append(append);
result = table.get(get);
assertTrue(result.isEmpty());
append = new Append(row1);
append.add(fam, qual, Bytes.toBytes("c"));
append.setCellVisibility(new CellVisibility(SECRET));
table.append(append);
result = table.get(get);
assertTrue(!result.isEmpty());
} finally {
if (table != null) {
table.close();
}
}
}
private static HTable createTableAndWriteDataWithLabels(TableName tableName, String... labelExps)
throws Exception {
HTable table = null;
try {
table = TEST_UTIL.createTable(tableName, fam);
int i = 1;
List<Put> puts = new ArrayList<Put>();
for (String labelExp : labelExps) {
Put put = new Put(Bytes.toBytes("row" + i));
put.add(fam, qual, HConstants.LATEST_TIMESTAMP, value);
put.setCellVisibility(new CellVisibility(labelExp));
puts.add(put);
i++;
}
table.put(puts);
} finally {
if (table != null) {
table.close();
}
}
return table;
}
private static void addLabels() throws Exception {
PrivilegedExceptionAction<VisibilityLabelsResponse> action =
new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
public VisibilityLabelsResponse run() throws Exception {
String[] labels = { SECRET, TOPSECRET, CONFIDENTIAL, PUBLIC, PRIVATE };
try {
VisibilityClient.addLabels(conf, labels);
} catch (Throwable t) {
throw new IOException(t);
}
return null;
}
};
SUPERUSER.runAs(action);
}
}

View File

@ -0,0 +1,175 @@
/**
* 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.hadoop.hbase.security.visibility;
import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABELS_TABLE_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.MediumTests;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.GetAuthsResponse;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsResponse;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.TestName;
import com.google.protobuf.ByteString;
@Category(MediumTests.class)
public class TestVisibilityLabelsOpWithDifferentUsersNoACL {
private static final String PRIVATE = "private";
private static final String CONFIDENTIAL = "confidential";
private static final String SECRET = "secret";
private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
private static Configuration conf;
@Rule
public final TestName TEST_NAME = new TestName();
private static User SUPERUSER;
private static User NORMAL_USER;
private static User NORMAL_USER1;
@BeforeClass
public static void setupBeforeClass() throws Exception {
// setup configuration
conf = TEST_UTIL.getConfiguration();
conf.setInt("hfile.format.version", 3);
String currentUser = User.getCurrent().getName();
conf.set("hbase.superuser", "admin,"+currentUser);
conf.set("hbase.coprocessor.master.classes", VisibilityController.class.getName());
conf.set("hbase.coprocessor.region.classes", VisibilityController.class.getName());
TEST_UTIL.startMiniCluster(2);
// Wait for the labels table to become available
TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000);
SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
NORMAL_USER = User.createUserForTesting(conf, "user1", new String[] {});
NORMAL_USER1 = User.createUserForTesting(conf, "user2", new String[] {});
addLabels();
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
TEST_UTIL.shutdownMiniCluster();
}
@Test
public void testLabelsTableOpsWithDifferentUsers() throws Throwable {
PrivilegedExceptionAction<VisibilityLabelsResponse> action =
new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
public VisibilityLabelsResponse run() throws Exception {
try {
return VisibilityClient.setAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user1");
} catch (Throwable e) {
}
return null;
}
};
VisibilityLabelsResponse response = SUPERUSER.runAs(action);
assertTrue(response.getResult(0).getException().getValue().isEmpty());
assertTrue(response.getResult(1).getException().getValue().isEmpty());
// Ideally this should not be allowed. this operation should fail or do nothing.
action = new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
public VisibilityLabelsResponse run() throws Exception {
try {
return VisibilityClient.setAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user3");
} catch (Throwable e) {
}
return null;
}
};
response = NORMAL_USER1.runAs(action);
assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response
.getResult(0).getException().getName());
assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response
.getResult(1).getException().getName());
PrivilegedExceptionAction<GetAuthsResponse> action1 =
new PrivilegedExceptionAction<GetAuthsResponse>() {
public GetAuthsResponse run() throws Exception {
try {
return VisibilityClient.getAuths(conf, "user1");
} catch (Throwable e) {
}
return null;
}
};
GetAuthsResponse authsResponse = NORMAL_USER.runAs(action1);
assertTrue(authsResponse.getAuthList().isEmpty());
authsResponse = NORMAL_USER1.runAs(action1);
assertTrue(authsResponse.getAuthList().isEmpty());
authsResponse = SUPERUSER.runAs(action1);
List<String> authsList = new ArrayList<String>();
for (ByteString authBS : authsResponse.getAuthList()) {
authsList.add(Bytes.toString(authBS.toByteArray()));
}
assertEquals(2, authsList.size());
assertTrue(authsList.contains(CONFIDENTIAL));
assertTrue(authsList.contains(PRIVATE));
PrivilegedExceptionAction<VisibilityLabelsResponse> action2 =
new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
public VisibilityLabelsResponse run() throws Exception {
try {
return VisibilityClient.clearAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user1");
} catch (Throwable e) {
}
return null;
}
};
response = NORMAL_USER1.runAs(action2);
assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response
.getResult(0).getException().getName());
assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response
.getResult(1).getException().getName());
response = SUPERUSER.runAs(action2);
assertTrue(response.getResult(0).getException().getValue().isEmpty());
assertTrue(response.getResult(1).getException().getValue().isEmpty());
authsResponse = SUPERUSER.runAs(action1);
assertTrue(authsResponse.getAuthList().isEmpty());
}
private static void addLabels() throws Exception {
PrivilegedExceptionAction<VisibilityLabelsResponse> action =
new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
public VisibilityLabelsResponse run() throws Exception {
String[] labels = { SECRET, CONFIDENTIAL, PRIVATE };
try {
VisibilityClient.addLabels(conf, labels);
} catch (Throwable t) {
throw new IOException(t);
}
return null;
}
};
SUPERUSER.runAs(action);
}
}

View File

@ -0,0 +1,273 @@
/**
* 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.hadoop.hbase.security.visibility;
import static org.apache.hadoop.hbase.security.visibility.VisibilityConstants.LABELS_TABLE_NAME;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import java.io.IOException;
import java.security.PrivilegedExceptionAction;
import java.util.ArrayList;
import java.util.List;
import org.apache.hadoop.conf.Configuration;
import org.apache.hadoop.hbase.HBaseTestingUtility;
import org.apache.hadoop.hbase.HConstants;
import org.apache.hadoop.hbase.MediumTests;
import org.apache.hadoop.hbase.TableName;
import org.apache.hadoop.hbase.client.Get;
import org.apache.hadoop.hbase.client.HTable;
import org.apache.hadoop.hbase.client.Put;
import org.apache.hadoop.hbase.client.Result;
import org.apache.hadoop.hbase.client.ResultScanner;
import org.apache.hadoop.hbase.client.Scan;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.GetAuthsResponse;
import org.apache.hadoop.hbase.protobuf.generated.VisibilityLabelsProtos.VisibilityLabelsResponse;
import org.apache.hadoop.hbase.security.User;
import org.apache.hadoop.hbase.security.access.AccessControlLists;
import org.apache.hadoop.hbase.security.access.AccessController;
import org.apache.hadoop.hbase.security.access.SecureTestUtil;
import org.apache.hadoop.hbase.util.Bytes;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Rule;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.rules.TestName;
import com.google.protobuf.ByteString;
@Category(MediumTests.class)
public class TestVisibilityLabelsWithACL {
private static final String PRIVATE = "private";
private static final String CONFIDENTIAL = "confidential";
private static final String SECRET = "secret";
private static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
private static final byte[] row1 = Bytes.toBytes("row1");
private final static byte[] fam = Bytes.toBytes("info");
private final static byte[] qual = Bytes.toBytes("qual");
private final static byte[] value = Bytes.toBytes("value");
private static Configuration conf;
@Rule
public final TestName TEST_NAME = new TestName();
private static User SUPERUSER;
private static User NORMAL_USER;
@BeforeClass
public static void setupBeforeClass() throws Exception {
// setup configuration
conf = TEST_UTIL.getConfiguration();
conf.setInt("hfile.format.version", 3);
SecureTestUtil.enableSecurity(conf);
conf.set("hbase.coprocessor.master.classes", AccessController.class.getName() + ","
+ VisibilityController.class.getName());
conf.set("hbase.coprocessor.region.classes", AccessController.class.getName() + ","
+ VisibilityController.class.getName());
TEST_UTIL.startMiniCluster(2);
TEST_UTIL.waitTableEnabled(AccessControlLists.ACL_TABLE_NAME.getName(), 50000);
// Wait for the labels table to become available
TEST_UTIL.waitTableEnabled(LABELS_TABLE_NAME.getName(), 50000);
SUPERUSER = User.createUserForTesting(conf, "admin", new String[] { "supergroup" });
NORMAL_USER = User.createUserForTesting(conf, "user1", new String[] {});
addLabels();
}
@AfterClass
public static void tearDownAfterClass() throws Exception {
TEST_UTIL.shutdownMiniCluster();
}
@Test
public void testScanForUserWithFewerLabelAuthsThanLabelsInScanAuthorizations() throws Throwable {
String[] auths = { SECRET };
String user = "admin";
VisibilityClient.setAuths(conf, auths, user);
TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
final HTable table = createTableAndWriteDataWithLabels(tableName, SECRET + "&" + CONFIDENTIAL
+ "&!" + PRIVATE, SECRET + "&!" + PRIVATE);
PrivilegedExceptionAction<Void> scanAction = new PrivilegedExceptionAction<Void>() {
public Void run() throws Exception {
Scan s = new Scan();
s.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL));
HTable t = new HTable(conf, table.getTableName());
try {
ResultScanner scanner = t.getScanner(s);
Result result = scanner.next();
assertTrue(!result.isEmpty());
assertTrue(Bytes.equals(Bytes.toBytes("row2"), result.getRow()));
result = scanner.next();
assertNull(result);
} finally {
t.close();
}
return null;
}
};
SUPERUSER.runAs(scanAction);
}
@Test
public void testVisibilityLabelsForUserWithNoAuths() throws Throwable {
String user = "admin";
String[] auths = { SECRET };
VisibilityClient.clearAuths(conf, auths, user); // Removing all auths if any.
VisibilityClient.setAuths(conf, auths, "user1");
TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
final HTable table = createTableAndWriteDataWithLabels(tableName, SECRET);
PrivilegedExceptionAction<Void> getAction = new PrivilegedExceptionAction<Void>() {
public Void run() throws Exception {
Get g = new Get(row1);
g.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL));
HTable t = new HTable(conf, table.getTableName());
try {
Result result = t.get(g);
assertTrue(result.isEmpty());
} finally {
t.close();
}
return null;
}
};
SUPERUSER.runAs(getAction);
}
@Test
public void testLabelsTableOpsWithDifferentUsers() throws Throwable {
PrivilegedExceptionAction<VisibilityLabelsResponse> action =
new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
public VisibilityLabelsResponse run() throws Exception {
try {
return VisibilityClient.addLabels(conf, new String[] { "l1", "l2" });
} catch (Throwable e) {
}
return null;
}
};
VisibilityLabelsResponse response = NORMAL_USER.runAs(action);
assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response
.getResult(0).getException().getName());
assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response
.getResult(1).getException().getName());
action = new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
public VisibilityLabelsResponse run() throws Exception {
try {
return VisibilityClient.setAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user1");
} catch (Throwable e) {
}
return null;
}
};
response = NORMAL_USER.runAs(action);
assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response
.getResult(0).getException().getName());
assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response
.getResult(1).getException().getName());
action = new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
public VisibilityLabelsResponse run() throws Exception {
try {
return VisibilityClient.setAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user1");
} catch (Throwable e) {
}
return null;
}
};
response = SUPERUSER.runAs(action);
assertTrue(response.getResult(0).getException().getValue().isEmpty());
assertTrue(response.getResult(1).getException().getValue().isEmpty());
action = new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
public VisibilityLabelsResponse run() throws Exception {
try {
return VisibilityClient.clearAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user1");
} catch (Throwable e) {
}
return null;
}
};
response = NORMAL_USER.runAs(action);
assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response.getResult(0)
.getException().getName());
assertEquals("org.apache.hadoop.hbase.security.AccessDeniedException", response.getResult(1)
.getException().getName());
response = VisibilityClient.clearAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user1");
assertTrue(response.getResult(0).getException().getValue().isEmpty());
assertTrue(response.getResult(1).getException().getValue().isEmpty());
VisibilityClient.setAuths(conf, new String[] { CONFIDENTIAL, PRIVATE }, "user2");
PrivilegedExceptionAction<GetAuthsResponse> action1 =
new PrivilegedExceptionAction<GetAuthsResponse>() {
public GetAuthsResponse run() throws Exception {
try {
return VisibilityClient.getAuths(conf, "user2");
} catch (Throwable e) {
}
return null;
}
};
GetAuthsResponse authsResponse = NORMAL_USER.runAs(action1);
assertNull(authsResponse);
authsResponse = SUPERUSER.runAs(action1);
List<String> authsList = new ArrayList<String>();
for (ByteString authBS : authsResponse.getAuthList()) {
authsList.add(Bytes.toString(authBS.toByteArray()));
}
assertEquals(2, authsList.size());
assertTrue(authsList.contains(CONFIDENTIAL));
assertTrue(authsList.contains(PRIVATE));
}
private static HTable createTableAndWriteDataWithLabels(TableName tableName, String... labelExps)
throws Exception {
HTable table = null;
try {
table = TEST_UTIL.createTable(tableName, fam);
int i = 1;
List<Put> puts = new ArrayList<Put>();
for (String labelExp : labelExps) {
Put put = new Put(Bytes.toBytes("row" + i));
put.add(fam, qual, HConstants.LATEST_TIMESTAMP, value);
put.setCellVisibility(new CellVisibility(labelExp));
puts.add(put);
i++;
}
table.put(puts);
} finally {
if (table != null) {
table.close();
}
}
return table;
}
private static void addLabels() throws IOException {
String[] labels = { SECRET, CONFIDENTIAL, PRIVATE };
try {
VisibilityClient.addLabels(conf, labels);
} catch (Throwable t) {
throw new IOException(t);
}
}
}

View File

@ -79,3 +79,4 @@ require 'hbase/admin'
require 'hbase/table'
require 'hbase/replication_admin'
require 'hbase/security'
require 'hbase/visibility_labels'

View File

@ -22,6 +22,7 @@ include Java
require 'hbase/admin'
require 'hbase/table'
require 'hbase/security'
require 'hbase/visibility_labels'
module Hbase
class Hbase
@ -55,5 +56,9 @@ module Hbase
def security_admin(formatter)
::Hbase::SecurityAdmin.new(configuration, formatter)
end
def visibility_labels_admin(formatter)
::Hbase::VisibilityLabelsAdmin.new(configuration, formatter)
end
end
end

View File

@ -0,0 +1,134 @@
#
# 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.
#
include Java
java_import org.apache.hadoop.hbase.security.visibility.VisibilityClient
java_import org.apache.hadoop.hbase.security.visibility.VisibilityConstants
java_import org.apache.hadoop.hbase.util.Bytes
module Hbase
class VisibilityLabelsAdmin
def initialize(configuration, formatter)
@config = configuration
@formatter = formatter
@admin = org.apache.hadoop.hbase.client.HBaseAdmin.new(configuration)
end
def add_labels(*args)
lables_table_available?
# Normalize args
if args.kind_of?(Array)
labels = [ args ].flatten.compact
end
begin
response = VisibilityClient.addLabels(@config, labels.to_java(:string))
if response.nil?
raise(ArgumentError, "DISABLED: Visibility labels feature is not available")
end
labelsWithException = ""
list = response.getResultList()
list.each do |result|
if result.hasException()
labelsWithException += Bytes.toString(result.getException().getValue().toByteArray())
end
end
if labelsWithException.length > 0
raise(ArgumentError, labelsWithException)
end
end
end
def set_auths(user, *args)
lables_table_available?
# Normalize args
if args.kind_of?(Array)
auths = [ args ].flatten.compact
end
begin
response = VisibilityClient.setAuths(@config, auths.to_java(:string), user)
if response.nil?
raise(ArgumentError, "DISABLED: Visibility labels feature is not available")
end
labelsWithException = ""
list = response.getResultList()
list.each do |result|
if result.hasException()
labelsWithException += Bytes.toString(result.getException().getValue().toByteArray())
end
end
if labelsWithException.length > 0
raise(ArgumentError, labelsWithException)
end
end
end
def get_auths(user)
lables_table_available?
begin
response = VisibilityClient.getAuths(@config, user)
if response.nil?
raise(ArgumentError, "DISABLED: Visibility labels feature is not available")
end
if response.getAuthList.empty?
raise(ArgumentError, "No authentication set for the given user " + user)
end
return response.getAuthList
end
end
def clear_auths(user, *args)
lables_table_available?
# Normalize args
if args.kind_of?(Array)
auths = [ args ].flatten.compact
end
begin
response = VisibilityClient.clearAuths(@config, auths.to_java(:string), user)
if response.nil?
raise(ArgumentError, "DISABLED: Visibility labels feature is not available")
end
labelsWithException = ""
list = response.getResultList()
list.each do |result|
if result.hasException()
labelsWithException += Bytes.toString(result.getException().getValue().toByteArray())
end
end
if labelsWithException.length > 0
raise(ArgumentError, labelsWithException)
end
end
end
# Make sure that lables table is available
def lables_table_available?()
raise(ArgumentError, "DISABLED: Visibility labels feature is not available") \
unless exists?(VisibilityConstants::LABELS_TABLE_NAME)
end
# Does table exist?
def exists?(table_name)
@admin.tableExists(table_name)
end
end
end

View File

@ -90,6 +90,10 @@ module Shell
@hbase_security_admin ||= hbase.security_admin(formatter)
end
def hbase_visibility_labels_admin
@hbase_visibility_labels_admin ||= hbase.visibility_labels_admin(formatter)
end
def export_commands(where)
::Shell.commands.keys.each do |cmd|
# here where is the IRB namespace
@ -346,3 +350,14 @@ Shell.load_command_group(
]
)
Shell.load_command_group(
'visibility labels',
:full_name => 'VISIBILITY LABEL TOOLS',
:comment => "NOTE: Above commands are only applicable if running with the VisibilityController coprocessor",
:commands => %w[
add_labels
set_auths
get_auths
clear_auths
]
)

View File

@ -62,6 +62,10 @@ module Shell
@shell.hbase_security_admin
end
def visibility_labels_admin
@shell.hbase_visibility_labels_admin
end
#----------------------------------------------------------------------
def formatter

View File

@ -0,0 +1,40 @@
#
# 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.
#
module Shell
module Commands
class AddLabels < Command
def help
return <<-EOF
Add a set of visibility labels.
Syntax : add_labels [label1, label2]
For example:
hbase> add_labels ['SECRET','PRIVATE']
EOF
end
def command(*args)
format_simple_command do
visibility_labels_admin.add_labels(args)
end
end
end
end
end

View File

@ -0,0 +1,39 @@
# 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.
#
module Shell
module Commands
class ClearAuths < Command
def help
return <<-EOF
Add a set of visibility labels for an user that has to removed
Syntax : clear_auths 'user1',[label1, label2]
For example:
hbase> clear_auths 'user1', ['SECRET','PRIVATE']
EOF
end
def command(user, *args)
format_simple_command do
visibility_labels_admin.clear_auths(user, args)
end
end
end
end
end

View File

@ -0,0 +1,42 @@
# 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.
#
module Shell
module Commands
class GetAuths < Command
def help
return <<-EOF
Get the visibility labels set for a particular user
Syntax : get_auths 'user1'
For example:
hbase> get_auths 'user1'
EOF
end
def command(user)
format_simple_command do
list = visibility_labels_admin.get_auths(user)
list.each do |auths|
formatter.row([org.apache.hadoop.hbase.util.Bytes::toStringBinary(auths.toByteArray)])
end
end
end
end
end
end

View File

@ -0,0 +1,39 @@
# 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.
#
module Shell
module Commands
class SetAuths < Command
def help
return <<-EOF
Add a set of visibility labels for an user
Syntax : set_auths 'user1',[label1, label2]
For example:
hbase> set_auths 'user1', ['SECRET','PRIVATE']
EOF
end
def command(user, *args)
format_simple_command do
visibility_labels_admin.set_auths(user, args)
end
end
end
end
end