Return-Path: X-Original-To: apmail-accumulo-commits-archive@www.apache.org Delivered-To: apmail-accumulo-commits-archive@www.apache.org Received: from mail.apache.org (hermes.apache.org [140.211.11.3]) by minotaur.apache.org (Postfix) with SMTP id 1D90E1842F for ; Mon, 4 Jan 2016 19:29:27 +0000 (UTC) Received: (qmail 92018 invoked by uid 500); 4 Jan 2016 19:29:27 -0000 Delivered-To: apmail-accumulo-commits-archive@accumulo.apache.org Received: (qmail 91977 invoked by uid 500); 4 Jan 2016 19:29:27 -0000 Mailing-List: contact commits-help@accumulo.apache.org; run by ezmlm Precedence: bulk List-Help: List-Unsubscribe: List-Post: List-Id: Reply-To: dev@accumulo.apache.org Delivered-To: mailing list commits@accumulo.apache.org Received: (qmail 91951 invoked by uid 99); 4 Jan 2016 19:29:26 -0000 Received: from git1-us-west.apache.org (HELO git1-us-west.apache.org) (140.211.11.23) by apache.org (qpsmtpd/0.29) with ESMTP; Mon, 04 Jan 2016 19:29:26 +0000 Received: by git1-us-west.apache.org (ASF Mail Server at git1-us-west.apache.org, from userid 33) id D8836E0570; Mon, 4 Jan 2016 19:29:26 +0000 (UTC) Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: kturner@apache.org To: commits@accumulo.apache.org Message-Id: X-Mailer: ASF-Git Admin Mailer Subject: accumulo git commit: ACCUMULO-3734 unescape auths when using AuthsContainer Date: Mon, 4 Jan 2016 19:29:26 +0000 (UTC) Repository: accumulo Updated Branches: refs/heads/1.6 e1e410058 -> e581d5b69 ACCUMULO-3734 unescape auths when using AuthsContainer Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/e581d5b6 Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/e581d5b6 Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/e581d5b6 Branch: refs/heads/1.6 Commit: e581d5b6919ae3b6ac5691bc059e763b262844c6 Parents: e1e4100 Author: Keith Turner Authored: Thu Dec 31 10:23:45 2015 -0500 Committer: Keith Turner Committed: Mon Jan 4 13:42:03 2016 -0500 ---------------------------------------------------------------------- .../core/security/VisibilityEvaluator.java | 62 +++++++++++++++++++- .../core/security/VisibilityEvaluatorTest.java | 42 ++++++++++++- 2 files changed, 101 insertions(+), 3 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/e581d5b6/core/src/main/java/org/apache/accumulo/core/security/VisibilityEvaluator.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/security/VisibilityEvaluator.java b/core/src/main/java/org/apache/accumulo/core/security/VisibilityEvaluator.java index 8535731..2338ed9 100644 --- a/core/src/main/java/org/apache/accumulo/core/security/VisibilityEvaluator.java +++ b/core/src/main/java/org/apache/accumulo/core/security/VisibilityEvaluator.java @@ -19,6 +19,8 @@ package org.apache.accumulo.core.security; import java.util.ArrayList; import org.apache.accumulo.core.constraints.Constraint.Environment; +import org.apache.accumulo.core.data.ArrayByteSequence; +import org.apache.accumulo.core.data.ByteSequence; import org.apache.accumulo.core.security.ColumnVisibility.Node; /** @@ -28,6 +30,62 @@ public class VisibilityEvaluator { private AuthorizationContainer auths; /** + * Authorizations in column visibility expression are in escaped form. Column visibility parsing does not unescape. This class wraps an AuthorizationContainer + * and unescapes auths before checking the wrapped container. + */ + private static class UnescapingAuthorizationContainer implements AuthorizationContainer { + + private AuthorizationContainer wrapped; + + UnescapingAuthorizationContainer(AuthorizationContainer wrapee) { + this.wrapped = wrapee; + } + + @Override + public boolean contains(ByteSequence auth) { + return wrapped.contains(unescape(auth)); + } + } + + static ByteSequence unescape(ByteSequence auth) { + int escapeCharCount = 0; + for (int i = 0; i < auth.length(); i++) { + byte b = auth.byteAt(i); + if (b == '"' || b == '\\') { + escapeCharCount++; + } + } + + if (escapeCharCount > 0) { + if (escapeCharCount % 2 == 1) { + throw new IllegalArgumentException("Illegal escape sequence in auth : " + auth); + } + + byte[] unescapedCopy = new byte[auth.length() - escapeCharCount / 2]; + int pos = 0; + for (int i = 0; i < auth.length(); i++) { + byte b = auth.byteAt(i); + if (b == '\\') { + i++; + b = auth.byteAt(i); + if (b != '"' && b != '\\') { + throw new IllegalArgumentException("Illegal escape sequence in auth : " + auth); + } + } else if (b == '"') { + // should only see quote after a slash + throw new IllegalArgumentException("Illegal escape sequence in auth : " + auth); + } + + unescapedCopy[pos++] = b; + } + + return new ArrayByteSequence(unescapedCopy); + } else { + return auth; + } + } + + /** * Creates a new {@link Authorizations} object with escaped forms of the authorizations in the given object. * * @param auths @@ -86,7 +144,7 @@ public class VisibilityEvaluator { * environment containing authorizations */ VisibilityEvaluator(Environment env) { - this.auths = env.getAuthorizationsContainer(); + this.auths = new UnescapingAuthorizationContainer(env.getAuthorizationsContainer()); } /** @@ -97,7 +155,7 @@ public class VisibilityEvaluator { * authorizations object */ public VisibilityEvaluator(Authorizations authorizations) { - this.auths = escape((Authorizations) authorizations); + this.auths = escape(authorizations); } /** http://git-wip-us.apache.org/repos/asf/accumulo/blob/e581d5b6/core/src/test/java/org/apache/accumulo/core/security/VisibilityEvaluatorTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/security/VisibilityEvaluatorTest.java b/core/src/test/java/org/apache/accumulo/core/security/VisibilityEvaluatorTest.java index 2996970..ed90c81 100644 --- a/core/src/test/java/org/apache/accumulo/core/security/VisibilityEvaluatorTest.java +++ b/core/src/test/java/org/apache/accumulo/core/security/VisibilityEvaluatorTest.java @@ -22,8 +22,12 @@ import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; +import org.apache.accumulo.core.constraints.Constraint; +import org.apache.accumulo.core.constraints.Constraint.Environment; +import org.apache.accumulo.core.data.ArrayByteSequence; import org.apache.accumulo.core.util.BadArgumentException; import org.apache.accumulo.core.util.ByteArraySet; +import org.easymock.EasyMock; import org.junit.Test; public class VisibilityEvaluatorTest { @@ -88,8 +92,19 @@ public class VisibilityEvaluatorTest { @Test public void testQuotedExpressions() throws VisibilityParseException { - VisibilityEvaluator ct = new VisibilityEvaluator(new Authorizations("A#C", "A\"C", "A\\C", "AC")); + Authorizations auths = new Authorizations("A#C", "A\"C", "A\\C", "AC"); + VisibilityEvaluator ct = new VisibilityEvaluator(auths); + runQuoteTest(ct); + + Environment env = EasyMock.createNiceMock(Constraint.Environment.class); + EasyMock.expect(env.getAuthorizationsContainer()).andReturn(auths); + EasyMock.replay(env); + ct = new VisibilityEvaluator(env); + runQuoteTest(ct); + } + + private void runQuoteTest(VisibilityEvaluator ct) throws VisibilityParseException { assertTrue(ct.evaluate(new ColumnVisibility(quote("A#C") + "|" + quote("A?C")))); assertTrue(ct.evaluate(new ColumnVisibility(new ColumnVisibility(quote("A#C") + "|" + quote("A?C")).flatten()))); assertTrue(ct.evaluate(new ColumnVisibility(quote("A\"C") + "&" + quote("A\\C")))); @@ -113,6 +128,31 @@ public class VisibilityEvaluatorTest { } @Test + public void testUnescape() { + assertEquals("a\"b", VisibilityEvaluator.unescape(new ArrayByteSequence("a\\\"b")).toString()); + assertEquals("a\\b", VisibilityEvaluator.unescape(new ArrayByteSequence("a\\\\b")).toString()); + assertEquals("a\\\"b", VisibilityEvaluator.unescape(new ArrayByteSequence("a\\\\\\\"b")).toString()); + assertEquals("\\\"", VisibilityEvaluator.unescape(new ArrayByteSequence("\\\\\\\"")).toString()); + assertEquals("a\\b\\c\\d", VisibilityEvaluator.unescape(new ArrayByteSequence("a\\\\b\\\\c\\\\d")).toString()); + + try { + VisibilityEvaluator.unescape(new ArrayByteSequence("a\\b")); + fail("Expected failure to unescape invalid escape sequence"); + } catch (IllegalArgumentException e) {} + + try { + VisibilityEvaluator.unescape(new ArrayByteSequence("a\\b\\c")); + fail("Expected failure to unescape invalid escape sequence"); + } catch (IllegalArgumentException e) {} + + try { + VisibilityEvaluator.unescape(new ArrayByteSequence("a\"b\\")); + fail("Expected failure to unescape invalid escape sequence"); + } catch (IllegalArgumentException e) {} + + } + + @Test public void testNonAscii() throws VisibilityParseException { VisibilityEvaluator ct = new VisibilityEvaluator(new Authorizations("五", "六", "八", "九", "五十"));