You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@hbase.apache.org by ra...@apache.org on 2014/08/14 09:20:16 UTC

git commit: HBASE-11438 - [Visibility Controller] Support UTF8 character as Visibility Labels (Ram)

Repository: hbase
Updated Branches:
  refs/heads/branch-1 cd59a023c -> ae2a94402


HBASE-11438 - [Visibility Controller] Support UTF8 character as Visibility
Labels (Ram)


Project: http://git-wip-us.apache.org/repos/asf/hbase/repo
Commit: http://git-wip-us.apache.org/repos/asf/hbase/commit/ae2a9440
Tree: http://git-wip-us.apache.org/repos/asf/hbase/tree/ae2a9440
Diff: http://git-wip-us.apache.org/repos/asf/hbase/diff/ae2a9440

Branch: refs/heads/branch-1
Commit: ae2a944027bc146efd20e3fe3498e4c717b7baed
Parents: cd59a02
Author: Ramkrishna <ra...@intel.com>
Authored: Thu Aug 14 12:48:57 2014 +0530
Committer: Ramkrishna <ra...@intel.com>
Committed: Thu Aug 14 12:48:57 2014 +0530

----------------------------------------------------------------------
 .../security/visibility/Authorizations.java     |  11 --
 .../security/visibility/CellVisibility.java     |  37 +++++++
 .../visibility/VisibilityLabelsValidator.java   |   8 +-
 .../apache/hadoop/hbase/client/TestScan.java    |  41 +------
 .../hadoop/hbase/rest/model/ScannerModel.java   |   8 +-
 .../security/visibility/ExpressionParser.java   | 107 +++++++++++++------
 .../visibility/VisibilityController.java        |  42 +++-----
 .../visibility/TestExpressionParser.java        |  95 +++++++++++++++-
 .../visibility/TestVisibilityLabels.java        |  85 ++++++++++++++-
 9 files changed, 302 insertions(+), 132 deletions(-)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/hbase/blob/ae2a9440/hbase-client/src/main/java/org/apache/hadoop/hbase/security/visibility/Authorizations.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/visibility/Authorizations.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/visibility/Authorizations.java
index 2a07625..a82d6d8 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/visibility/Authorizations.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/visibility/Authorizations.java
@@ -36,22 +36,11 @@ public class Authorizations {
   public Authorizations(String... labels) {
     this.labels = new ArrayList<String>(labels.length);
     for (String label : labels) {
-      validateLabel(label);
       this.labels.add(label);
     }
   }
 
-  private void validateLabel(String label) {
-    if (!VisibilityLabelsValidator.isValidLabel(label)) {
-      throw new IllegalArgumentException("Invalid authorization label : " + label
-          + ". Authorizations cannot contain '(', ')' ,'&' ,'|', '!'" + " and cannot be empty");
-    }
-  }
-
   public Authorizations(List<String> labels) {
-    for (String label : labels) {
-      validateLabel(label);
-    }
     this.labels = labels;
   }
 

http://git-wip-us.apache.org/repos/asf/hbase/blob/ae2a9440/hbase-client/src/main/java/org/apache/hadoop/hbase/security/visibility/CellVisibility.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/visibility/CellVisibility.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/visibility/CellVisibility.java
index 3bd527b..0e71a0a 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/visibility/CellVisibility.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/visibility/CellVisibility.java
@@ -19,6 +19,7 @@ package org.apache.hadoop.hbase.security.visibility;
 
 import org.apache.hadoop.classification.InterfaceAudience;
 import org.apache.hadoop.classification.InterfaceStability;
+import org.apache.hadoop.hbase.util.Bytes;
 
 /**
  * This contains a visibility expression which can be associated with a cell. When it is set with a
@@ -46,4 +47,40 @@ public class CellVisibility {
   public String toString() {
     return this.expression;
   }
+
+  /**
+   * Helps in quoting authentication Strings. Use this if unicode characters to
+   * be used in expression or special characters like '(', ')',
+   * '"','\','&','|','!'
+   */
+  public static String quote(String auth) {
+    return quote(Bytes.toBytes(auth));
+  }
+
+  /**
+   * Helps in quoting authentication Strings. Use this if unicode characters to
+   * be used in expression or special characters like '(', ')',
+   * '"','\','&','|','!'
+   */
+  public static String quote(byte[] auth) {
+    int escapeChars = 0;
+
+    for (int i = 0; i < auth.length; i++)
+      if (auth[i] == '"' || auth[i] == '\\')
+        escapeChars++;
+
+    byte[] escapedAuth = new byte[auth.length + escapeChars + 2];
+    int index = 1;
+    for (int i = 0; i < auth.length; i++) {
+      if (auth[i] == '"' || auth[i] == '\\') {
+        escapedAuth[index++] = '\\';
+      }
+      escapedAuth[index++] = auth[i];
+    }
+
+    escapedAuth[0] = '"';
+    escapedAuth[escapedAuth.length - 1] = '"';
+
+    return Bytes.toString(escapedAuth);
+  }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/ae2a9440/hbase-client/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityLabelsValidator.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityLabelsValidator.java b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityLabelsValidator.java
index 9700b55..49b1778 100644
--- a/hbase-client/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityLabelsValidator.java
+++ b/hbase-client/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityLabelsValidator.java
@@ -17,7 +17,6 @@
  */
 package org.apache.hadoop.hbase.security.visibility;
 
-import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
 import org.apache.hadoop.classification.InterfaceAudience;
@@ -60,7 +59,7 @@ public class VisibilityLabelsValidator {
     return validAuthChars[0xff & b];
   }
 
-  static final boolean isValidLabel(byte[] label) {
+  public static final boolean isValidLabel(byte[] label) {
     for (int i = 0; i < label.length; i++) {
       if (!isValidAuthChar(label[i])) {
         return false;
@@ -68,9 +67,4 @@ public class VisibilityLabelsValidator {
     }
     return true;
   }
-
-  public static final boolean isValidLabel(String label) {
-    Matcher matcher = pattern.matcher(label);
-    return matcher.matches();
-  }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/ae2a9440/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java
----------------------------------------------------------------------
diff --git a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java
index 97c5f0f..10da121 100644
--- a/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java
+++ b/hbase-client/src/test/java/org/apache/hadoop/hbase/client/TestScan.java
@@ -114,56 +114,21 @@ public class TestScan {
   @Test
   public void testSetAuthorizations() {
     Scan scan = new Scan();
-    scan.setAuthorizations(new Authorizations("A", "B", "0123", "A0", "1A1", "_a"));
     try {
+      scan.setAuthorizations(new Authorizations("\u002b|\u0029"));
+      scan.setAuthorizations(new Authorizations("A", "B", "0123", "A0", "1A1", "_a"));
       scan.setAuthorizations(new Authorizations("A|B"));
-      fail("Should have failed for A|B.");
-    } catch (IllegalArgumentException e) {
-    }
-    try {
       scan.setAuthorizations(new Authorizations("A&B"));
-      fail("Should have failed for A&B.");
-    } catch (IllegalArgumentException e) {
-    }
-    try {
       scan.setAuthorizations(new Authorizations("!B"));
-      fail("Should have failed for !B.");
-    } catch (IllegalArgumentException e) {
-    }
-    try {
       scan.setAuthorizations(new Authorizations("A", "(A)"));
-      fail("Should have failed for (A).");
-    } catch (IllegalArgumentException e) {
-    }
-    try {
       scan.setAuthorizations(new Authorizations("A", "{A"));
-      fail("Should have failed for {A.");
-    } catch (IllegalArgumentException e) {
-    }
-    try {
       scan.setAuthorizations(new Authorizations(" "));
-      fail("Should have failed for empty");
-    } catch (IllegalArgumentException e) {
-    }
-    try {
       scan.setAuthorizations(new Authorizations(":B"));
-    } catch (IllegalArgumentException e) {
-      fail("Should not have failed for :B");
-    }
-    try {
       scan.setAuthorizations(new Authorizations("-B"));
-    } catch (IllegalArgumentException e) {
-      fail("Should not have failed for -B");
-    }
-    try {
       scan.setAuthorizations(new Authorizations(".B"));
-    } catch (IllegalArgumentException e) {
-      fail("Should not have failed for .B");
-    }
-    try {
       scan.setAuthorizations(new Authorizations("/B"));
     } catch (IllegalArgumentException e) {
-      fail("Should not have failed for /B");
+      fail("should not throw exception");
     }
   }
 }

http://git-wip-us.apache.org/repos/asf/hbase/blob/ae2a9440/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/model/ScannerModel.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/model/ScannerModel.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/model/ScannerModel.java
index 2fa53f4..1fc0a5d 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/model/ScannerModel.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/rest/model/ScannerModel.java
@@ -70,12 +70,11 @@ import org.apache.hadoop.hbase.filter.WhileMatchFilter;
 import org.apache.hadoop.hbase.rest.ProtobufMessageHandler;
 import org.apache.hadoop.hbase.rest.protobuf.generated.ScannerMessage.Scanner;
 import org.apache.hadoop.hbase.security.visibility.Authorizations;
-import org.apache.hadoop.hbase.security.visibility.VisibilityLabelsValidator;
 import org.apache.hadoop.hbase.util.Base64;
+import org.apache.hadoop.hbase.util.ByteStringer;
 import org.apache.hadoop.hbase.util.Bytes;
 
 import com.google.protobuf.ByteString;
-import org.apache.hadoop.hbase.util.ByteStringer;
 import com.sun.jersey.api.json.JSONConfiguration;
 import com.sun.jersey.api.json.JSONJAXBContext;
 import com.sun.jersey.api.json.JSONMarshaller;
@@ -527,11 +526,6 @@ public class ScannerModel implements ProtobufMessageHandler, Serializable {
     if (authorizations != null) {
       List<String> labels = authorizations.getLabels();
       for (String label : labels) {
-        if (!VisibilityLabelsValidator.isValidLabel(label)) {
-          throw new IllegalArgumentException("Invalid authorization label : " + label
-              + ". Authorizations cannot contain '(', ')' ,'&' ,'|', '!'" + " " +
-              		"and cannot be empty");
-        }
         model.addLabel(label);
       }
     }

http://git-wip-us.apache.org/repos/asf/hbase/blob/ae2a9440/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/ExpressionParser.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/ExpressionParser.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/ExpressionParser.java
index f6ddf75..bb17b48 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/ExpressionParser.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/ExpressionParser.java
@@ -17,6 +17,8 @@
  */
 package org.apache.hadoop.hbase.security.visibility;
 
+import java.util.ArrayList;
+import java.util.List;
 import java.util.Stack;
 
 import org.apache.hadoop.classification.InterfaceAudience;
@@ -35,49 +37,80 @@ public class ExpressionParser {
   private static final char AND = '&';
   private static final char NOT = '!';
   private static final char SPACE = ' ';
-
+  private static final char DOUBLE_QUOTES = '"';
   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);
+    int endPos = exp.length;
     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);
+        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;
+        case DOUBLE_QUOTES:
+          int labelOffset = ++index;
+          // We have to rewrite the expression within double quotes as incase of expressions 
+          // with escape characters we may have to avoid them as the original expression did
+          // not have them
+          List<Byte> list = new ArrayList<Byte>();
+          while (index < endPos && !endDoubleQuotesFound(exp[index])) {
+            if (exp[index] == '\\') {
+              index++;
+              if (exp[index] != '\\' && exp[index] != '"')
+                throw new ParseException("invalid escaping with quotes " + expS + " at column : "
+                    + index);
+            }
+            list.add(exp[index]);
+            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);
+          // The expression has come to the end. still no double quotes found 
+          if(index == endPos) {
+            throw new ParseException("No terminating quotes " + expS + " at column : " + index);
+          }
+          // This could be costly. but do we have any alternative?
+          // If we don't do this way then we may have to handle while checking the authorizations.
+          // Better to do it here.
+          byte[] array = com.google.common.primitives.Bytes.toArray(list);
+          String leafExp = new String(array).trim();
+          if (leafExp.isEmpty()) {
+            throw new ParseException("Error parsing expression " + expS + " at column : " + index);
+          }
+          processLabelExpNode(new LeafExpressionNode(leafExp), expStack, expS, index);
+          index = skipSpaces(exp, index);
+          break;
+        default:
+          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]));
+          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++;
     }
@@ -255,8 +288,12 @@ public class ExpressionParser {
     expStack.push(new NonLeafExpressionNode(Operator.NOT));
   }
 
+  private static boolean endDoubleQuotesFound(byte b) {
+    return (b == DOUBLE_QUOTES);
+  }
   private static boolean isEndOfLabel(byte b) {
-    return (b == OPEN_PARAN || b == CLOSE_PARAN || b == OR || b == AND || b == NOT || b == SPACE);
+    return (b == OPEN_PARAN || b == CLOSE_PARAN || b == OR || b == AND || 
+        b == NOT || b == SPACE);
   }
 
   private static Operator getOperator(byte op) {

http://git-wip-us.apache.org/repos/asf/hbase/blob/ae2a9440/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityController.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityController.java b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityController.java
index 661d188..9439ea5 100644
--- a/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityController.java
+++ b/hbase-server/src/main/java/org/apache/hadoop/hbase/security/visibility/VisibilityController.java
@@ -53,11 +53,11 @@ import org.apache.hadoop.hbase.HTableDescriptor;
 import org.apache.hadoop.hbase.KeyValue;
 import org.apache.hadoop.hbase.KeyValue.Type;
 import org.apache.hadoop.hbase.KeyValueUtil;
-import org.apache.hadoop.hbase.MetaTableAccessor;
 import org.apache.hadoop.hbase.NamespaceDescriptor;
 import org.apache.hadoop.hbase.ServerName;
 import org.apache.hadoop.hbase.TableName;
 import org.apache.hadoop.hbase.Tag;
+import org.apache.hadoop.hbase.MetaTableAccessor;
 import org.apache.hadoop.hbase.client.Append;
 import org.apache.hadoop.hbase.client.Delete;
 import org.apache.hadoop.hbase.client.Get;
@@ -1149,13 +1149,6 @@ public class VisibilityController extends BaseRegionObserver implements MasterOb
       if (table.isSystemTable() && !table.equals(LABELS_TABLE_NAME)) {
         return null;
       }
-    } else {
-      for (String label : authorizations.getLabels()) {
-        if (!VisibilityLabelsValidator.isValidLabel(label)) {
-          throw new IllegalArgumentException("Invalid authorization label : " + label
-              + ". Authorizations cannot contain '(', ')' ,'&' ,'|', '!'" + " and cannot be empty");
-        }
-      }
     }
     Filter visibilityLabelFilter = null;
     if (this.scanLabelGenerators != null) {
@@ -1310,30 +1303,21 @@ public class VisibilityController extends BaseRegionObserver implements MasterOb
       for (VisibilityLabel visLabel : labels) {
         byte[] label = visLabel.getLabel().toByteArray();
         String labelStr = Bytes.toString(label);
-        if (VisibilityLabelsValidator.isValidLabel(label)) {
-          if (this.visibilityManager.getLabelOrdinal(labelStr) > 0) {
-            RegionActionResult.Builder failureResultBuilder = RegionActionResult.newBuilder();
-            failureResultBuilder.setException(ResponseConverter
-                .buildException(new LabelAlreadyExistsException("Label '" + labelStr
-                    + "' already exists")));
-            response.addResult(failureResultBuilder.build());
-          } else {
-            Put p = new Put(Bytes.toBytes(ordinalCounter));
-            p.addImmutable(
-                LABELS_TABLE_FAMILY, LABEL_QUALIFIER, label, LABELS_TABLE_TAGS);
-            if (LOG.isDebugEnabled()) {
-              LOG.debug("Adding the label "+labelStr);
-            }
-            puts.add(p);
-            ordinalCounter++;
-            response.addResult(successResult);
-          }
-        } else {
+        if (this.visibilityManager.getLabelOrdinal(labelStr) > 0) {
           RegionActionResult.Builder failureResultBuilder = RegionActionResult.newBuilder();
           failureResultBuilder.setException(ResponseConverter
-              .buildException(new InvalidLabelException("Invalid visibility label '" + labelStr
-                  + "'")));
+              .buildException(new LabelAlreadyExistsException("Label '" + labelStr
+                  + "' already exists")));
           response.addResult(failureResultBuilder.build());
+        } else {
+          Put p = new Put(Bytes.toBytes(ordinalCounter));
+          p.addImmutable(LABELS_TABLE_FAMILY, LABEL_QUALIFIER, label, LABELS_TABLE_TAGS);
+          if (LOG.isDebugEnabled()) {
+            LOG.debug("Adding the label " + labelStr);
+          }
+          puts.add(p);
+          ordinalCounter++;
+          response.addResult(successResult);
         }
       }
       OperationStatus[] opStatus = this.regionEnv.getRegion().batchMutate(

http://git-wip-us.apache.org/repos/asf/hbase/blob/ae2a9440/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestExpressionParser.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestExpressionParser.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestExpressionParser.java
index f7a8dfd..ed2a1d5 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestExpressionParser.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestExpressionParser.java
@@ -17,9 +17,9 @@
  */
 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 static org.junit.Assert.fail;
 
 import org.apache.hadoop.hbase.SmallTests;
 import org.apache.hadoop.hbase.security.visibility.expression.ExpressionNode;
@@ -308,6 +308,99 @@ public class TestExpressionParser {
     executeNegativeCase("! a");
   }
 
+  @Test
+  public void testNonAsciiCases() throws Exception {
+    ExpressionNode node = parser.parse(CellVisibility.quote("\u0027") + "&"
+        + CellVisibility.quote("\u002b") + "|" + CellVisibility.quote("\u002d") + "&"
+        + CellVisibility.quote("\u003f"));
+    assertTrue(node instanceof NonLeafExpressionNode);
+    NonLeafExpressionNode nlNode = (NonLeafExpressionNode) node;
+    assertEquals(Operator.AND, nlNode.getOperator());
+    assertEquals(2, nlNode.getChildExps().size());
+    assertEquals("\u003f", ((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("\u002d", ((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("\u002b", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
+    assertEquals("\u0027", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
+
+    node = parser.parse(CellVisibility.quote("\u0027") + "&" + CellVisibility.quote("\u002b") + "|"
+        + CellVisibility.quote("\u002d") + "&" + CellVisibility.quote("\u003f"));
+    assertTrue(node instanceof NonLeafExpressionNode);
+    nlNode = (NonLeafExpressionNode) node;
+    assertEquals(Operator.AND, nlNode.getOperator());
+    assertEquals(2, nlNode.getChildExps().size());
+    assertEquals("\u003f", ((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("\u002d", ((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("\u002b", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
+    assertEquals("\u0027", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
+  }
+
+  @Test
+  public void testCasesSeperatedByDoubleQuotes() throws Exception {
+    ExpressionNode node = null;
+    try {
+      node = parser.parse("\u0027&\"|\u002b&\u003f");
+      fail("Excpetion must be thrown as there are special characters without quotes");
+    } catch (ParseException e) {
+    }
+    node = parser.parse(CellVisibility.quote("\u0027") + "&" + CellVisibility.quote("\"") + "|"
+        + CellVisibility.quote("\u002b" + "&" + "\u003f"));
+    assertTrue(node instanceof NonLeafExpressionNode);
+    NonLeafExpressionNode nlNode = (NonLeafExpressionNode) node;
+    assertEquals(Operator.OR, nlNode.getOperator());
+    assertEquals(2, nlNode.getChildExps().size());
+    assertEquals("\u002b" + "&" + "\u003f",
+        ((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("\"", ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
+    assertEquals("\u0027", ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
+    try {
+      node = parser.parse(CellVisibility.quote("\u0027&\\") + "|"
+          + CellVisibility.quote("\u002b" + "&" + "\\") + CellVisibility.quote("$$\""));
+      fail("Excpetion must be thrown as there is not operator");
+    } catch (ParseException e) {
+    }
+    node = parser.parse(CellVisibility.quote("\u0027" + "&" + "\\") + "|"
+        + CellVisibility.quote("\u003f" + "&" + "\\") + "&" + CellVisibility.quote("$$\""));
+    assertTrue(node instanceof NonLeafExpressionNode);
+    nlNode = (NonLeafExpressionNode) node;
+    assertEquals(Operator.AND, nlNode.getOperator());
+    assertEquals(2, nlNode.getChildExps().size());
+    assertEquals("$$\"", ((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("\u0027" + "&" + "\\",
+        ((LeafExpressionNode) nlNode.getChildExps().get(0)).getIdentifier());
+    assertEquals("\u003f" + "&" + "\\",
+        ((LeafExpressionNode) nlNode.getChildExps().get(1)).getIdentifier());
+    try {
+      node = parser.parse(CellVisibility.quote("\u002b&\\") + "|" + CellVisibility.quote("\u0027&\\") + "&"
+          + "\"$$");
+      fail("Excpetion must be thrown as there is no end quote");
+    } catch (ParseException e) {
+    }
+  }
+
   private void executeNegativeCase(String exp) {
     try {
       parser.parse(exp);

http://git-wip-us.apache.org/repos/asf/hbase/blob/ae2a9440/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabels.java
----------------------------------------------------------------------
diff --git a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabels.java b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabels.java
index 84ecf6a..654dfd9 100644
--- a/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabels.java
+++ b/hbase-server/src/test/java/org/apache/hadoop/hbase/security/visibility/TestVisibilityLabels.java
@@ -83,6 +83,12 @@ public class TestVisibilityLabels {
   private static final String PRIVATE = "private";
   private static final String CONFIDENTIAL = "confidential";
   private static final String SECRET = "secret";
+  private static final String COPYRIGHT = "\u00A9ABC";
+  private static final String ACCENT = "\u0941";
+  private static final String UNICODE_VIS_TAG = COPYRIGHT + "\"" + ACCENT + "\\" + SECRET + "\""
+      + "\u0027&\\";
+  private static final String UC1 = "\u0027\"\u002b";
+  private static final String UC2 = "\u002d\u003f";
   public static final HBaseTestingUtility TEST_UTIL = new HBaseTestingUtility();
   private static final byte[] row1 = Bytes.toBytes("row1");
   private static final byte[] row2 = Bytes.toBytes("row2");
@@ -154,6 +160,77 @@ public class TestVisibilityLabels {
       }
     }
   }
+  
+  @Test
+  public void testSimpleVisibilityLabelsWithUniCodeCharacters() throws Exception {
+    TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
+    HTable table = createTableAndWriteDataWithLabels(tableName,
+        SECRET + "|" + CellVisibility.quote(COPYRIGHT), "(" + CellVisibility.quote(COPYRIGHT) + "&"
+            + CellVisibility.quote(ACCENT) + ")|" + CONFIDENTIAL,
+        CellVisibility.quote(UNICODE_VIS_TAG) + "&" + SECRET);
+    try {
+      Scan s = new Scan();
+      s.setAuthorizations(new Authorizations(SECRET, CONFIDENTIAL, PRIVATE, COPYRIGHT, ACCENT,
+          UNICODE_VIS_TAG));
+      ResultScanner scanner = table.getScanner(s);
+      Result[] next = scanner.next(3);
+      assertTrue(next.length == 3);
+      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));
+      cellScanner = next[2].cellScanner();
+      cellScanner.advance();
+      current = cellScanner.current();
+      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
+          current.getRowLength(), row3, 0, row3.length));
+    } finally {
+      if (table != null) {
+        table.close();
+      }
+    }
+  }
+
+  @Test
+  public void testAuthorizationsWithSpecialUnicodeCharacters() throws Exception {
+    TableName tableName = TableName.valueOf(TEST_NAME.getMethodName());
+    HTable table = createTableAndWriteDataWithLabels(tableName,
+        CellVisibility.quote(UC1) + "|" + CellVisibility.quote(UC2), CellVisibility.quote(UC1),
+        CellVisibility.quote(UNICODE_VIS_TAG));
+    try {
+      Scan s = new Scan();
+      s.setAuthorizations(new Authorizations(UC1, UC2, ACCENT,
+          UNICODE_VIS_TAG));
+      ResultScanner scanner = table.getScanner(s);
+      Result[] next = scanner.next(3);
+      assertTrue(next.length == 3);
+      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));
+      cellScanner = next[2].cellScanner();
+      cellScanner.advance();
+      current = cellScanner.current();
+      assertTrue(Bytes.equals(current.getRowArray(), current.getRowOffset(),
+          current.getRowLength(), row3, 0, row3.length));
+    } finally {
+      if (table != null) {
+        table.close();
+      }
+    }
+  }
 
   @Test
   public void testVisibilityLabelsWithComplexLabels() throws Exception {
@@ -406,7 +483,7 @@ public class TestVisibilityLabels {
       }
     }
     // One label is the "system" label.
-    Assert.assertEquals("The count should be 8", 8, i);
+    Assert.assertEquals("The count should be 13", 13, i);
   }
 
   private void waitForLabelsRegionAvailability(HRegionServer regionServer) {
@@ -466,8 +543,7 @@ public class TestVisibilityLabels {
         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(3).getException().getValue().isEmpty());
         assertTrue(resultList.get(4).getException().getValue().isEmpty());
         return null;
       }
@@ -929,7 +1005,8 @@ public class TestVisibilityLabels {
     PrivilegedExceptionAction<VisibilityLabelsResponse> action =
         new PrivilegedExceptionAction<VisibilityLabelsResponse>() {
       public VisibilityLabelsResponse run() throws Exception {
-        String[] labels = { SECRET, TOPSECRET, CONFIDENTIAL, PUBLIC, PRIVATE };
+        String[] labels = { SECRET, TOPSECRET, CONFIDENTIAL, PUBLIC, PRIVATE, COPYRIGHT, ACCENT,
+            UNICODE_VIS_TAG, UC1, UC2 };
         try {
           VisibilityClient.addLabels(conf, labels);
         } catch (Throwable t) {