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:
parent
dc20322a6a
commit
5a6a0fd78b
|
@ -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;
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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_";
|
||||
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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();
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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];
|
||||
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
|
@ -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.
|
||||
*/
|
||||
|
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
|
@ -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);
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
File diff suppressed because it is too large
Load Diff
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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();
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
};
|
||||
}
|
|
@ -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());
|
||||
}
|
||||
}
|
|
@ -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) {
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -79,3 +79,4 @@ require 'hbase/admin'
|
|||
require 'hbase/table'
|
||||
require 'hbase/replication_admin'
|
||||
require 'hbase/security'
|
||||
require 'hbase/visibility_labels'
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
]
|
||||
)
|
|
@ -62,6 +62,10 @@ module Shell
|
|||
@shell.hbase_security_admin
|
||||
end
|
||||
|
||||
def visibility_labels_admin
|
||||
@shell.hbase_visibility_labels_admin
|
||||
end
|
||||
|
||||
#----------------------------------------------------------------------
|
||||
|
||||
def formatter
|
||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
Loading…
Reference in New Issue