Updated Branches: refs/heads/master f479cad58 -> d9ab84498
ACCUMULO-1312 Test Connectors and serialization with destroyed tokens Project: http://git-wip-us.apache.org/repos/asf/accumulo/repo Commit: http://git-wip-us.apache.org/repos/asf/accumulo/commit/d9ab8449 Tree: http://git-wip-us.apache.org/repos/asf/accumulo/tree/d9ab8449 Diff: http://git-wip-us.apache.org/repos/asf/accumulo/diff/d9ab8449 Branch: refs/heads/master Commit: d9ab84498cad5ee70eee3d337224b3d5ca7ab0db Parents: f479cad Author: Christopher Tubbs <[email protected]> Authored: Mon Jul 29 15:57:21 2013 -0400 Committer: Christopher Tubbs <[email protected]> Committed: Mon Jul 29 15:57:21 2013 -0400 ---------------------------------------------------------------------- .../core/client/impl/ConnectorImpl.java | 3 + .../core/client/mock/MockConnector.java | 14 ++- .../accumulo/core/client/mock/MockInstance.java | 3 +- .../client/security/tokens/PasswordToken.java | 4 +- .../accumulo/core/security/Credentials.java | 7 +- .../accumulo/core/security/CredentialsTest.java | 51 +++++++++++ .../accumulo/test/functional/CredentialsIT.java | 96 ++++++++++++++++++++ 7 files changed, 171 insertions(+), 7 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/accumulo/blob/d9ab8449/core/src/main/java/org/apache/accumulo/core/client/impl/ConnectorImpl.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/impl/ConnectorImpl.java b/core/src/main/java/org/apache/accumulo/core/client/impl/ConnectorImpl.java index 14df55f..bd11569 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/impl/ConnectorImpl.java +++ b/core/src/main/java/org/apache/accumulo/core/client/impl/ConnectorImpl.java @@ -55,6 +55,9 @@ public class ConnectorImpl extends Connector { public ConnectorImpl(final Instance instance, Credentials cred) throws AccumuloException, AccumuloSecurityException { ArgumentChecker.notNull(instance, cred); + if (cred.getToken().isDestroyed()) + throw new AccumuloSecurityException(cred.getPrincipal(), SecurityErrorCode.TOKEN_EXPIRED); + this.instance = instance; this.credentials = cred; http://git-wip-us.apache.org/repos/asf/accumulo/blob/d9ab8449/core/src/main/java/org/apache/accumulo/core/client/mock/MockConnector.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/mock/MockConnector.java b/core/src/main/java/org/apache/accumulo/core/client/mock/MockConnector.java index 4af2ea5..80ec513 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/mock/MockConnector.java +++ b/core/src/main/java/org/apache/accumulo/core/client/mock/MockConnector.java @@ -18,6 +18,7 @@ package org.apache.accumulo.core.client.mock; import java.util.concurrent.TimeUnit; +import org.apache.accumulo.core.client.AccumuloSecurityException; import org.apache.accumulo.core.client.BatchDeleter; import org.apache.accumulo.core.client.BatchScanner; import org.apache.accumulo.core.client.BatchWriter; @@ -32,7 +33,10 @@ import org.apache.accumulo.core.client.TableNotFoundException; import org.apache.accumulo.core.client.admin.InstanceOperations; import org.apache.accumulo.core.client.admin.SecurityOperations; import org.apache.accumulo.core.client.admin.TableOperations; +import org.apache.accumulo.core.client.impl.thrift.SecurityErrorCode; +import org.apache.accumulo.core.client.security.tokens.NullToken; import org.apache.accumulo.core.security.Authorizations; +import org.apache.accumulo.core.security.Credentials; public class MockConnector extends Connector { @@ -40,12 +44,14 @@ public class MockConnector extends Connector { private final MockAccumulo acu; private final Instance instance; - MockConnector(String username, MockInstance instance) { - this(username, new MockAccumulo(MockInstance.getDefaultFileSystem()), instance); + MockConnector(String username, MockInstance instance) throws AccumuloSecurityException { + this(new Credentials(username, new NullToken()), new MockAccumulo(MockInstance.getDefaultFileSystem()), instance); } - MockConnector(String username, MockAccumulo acu, MockInstance instance) { - this.username = username; + MockConnector(Credentials credentials, MockAccumulo acu, MockInstance instance) throws AccumuloSecurityException { + if (credentials.getToken().isDestroyed()) + throw new AccumuloSecurityException(credentials.getPrincipal(), SecurityErrorCode.TOKEN_EXPIRED); + this.username = credentials.getPrincipal(); this.acu = acu; this.instance = instance; } http://git-wip-us.apache.org/repos/asf/accumulo/blob/d9ab8449/core/src/main/java/org/apache/accumulo/core/client/mock/MockInstance.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/mock/MockInstance.java b/core/src/main/java/org/apache/accumulo/core/client/mock/MockInstance.java index f37994d..2ba8c67 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/mock/MockInstance.java +++ b/core/src/main/java/org/apache/accumulo/core/client/mock/MockInstance.java @@ -31,6 +31,7 @@ import org.apache.accumulo.core.client.impl.thrift.SecurityErrorCode; import org.apache.accumulo.core.client.security.tokens.AuthenticationToken; import org.apache.accumulo.core.client.security.tokens.PasswordToken; import org.apache.accumulo.core.conf.AccumuloConfiguration; +import org.apache.accumulo.core.security.Credentials; import org.apache.accumulo.core.util.ByteBufferUtil; import org.apache.accumulo.core.util.CachedConfiguration; import org.apache.accumulo.core.util.TextUtil; @@ -150,7 +151,7 @@ public class MockInstance implements Instance { @Override public Connector getConnector(String principal, AuthenticationToken token) throws AccumuloException, AccumuloSecurityException { - Connector conn = new MockConnector(principal, acu, this); + Connector conn = new MockConnector(new Credentials(principal, token), acu, this); if (!acu.users.containsKey(principal)) conn.securityOperations().createLocalUser(principal, (PasswordToken) token); else if (!acu.users.get(principal).token.equals(token)) http://git-wip-us.apache.org/repos/asf/accumulo/blob/d9ab8449/core/src/main/java/org/apache/accumulo/core/client/security/tokens/PasswordToken.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/client/security/tokens/PasswordToken.java b/core/src/main/java/org/apache/accumulo/core/client/security/tokens/PasswordToken.java index c39fb8d..11bbf49 100644 --- a/core/src/main/java/org/apache/accumulo/core/client/security/tokens/PasswordToken.java +++ b/core/src/main/java/org/apache/accumulo/core/client/security/tokens/PasswordToken.java @@ -46,7 +46,9 @@ public class PasswordToken implements AuthenticationToken { /** * Constructor for use with {@link Writable}. Call {@link #readFields(DataInput)}. */ - public PasswordToken() {} + public PasswordToken() { + password = new byte[0]; + } /** * Constructs a token from a copy of the password. Destroying the argument after construction will not destroy the copy in this token, and destroying this http://git-wip-us.apache.org/repos/asf/accumulo/blob/d9ab8449/core/src/main/java/org/apache/accumulo/core/security/Credentials.java ---------------------------------------------------------------------- diff --git a/core/src/main/java/org/apache/accumulo/core/security/Credentials.java b/core/src/main/java/org/apache/accumulo/core/security/Credentials.java index 71a09f6..0552e7e 100644 --- a/core/src/main/java/org/apache/accumulo/core/security/Credentials.java +++ b/core/src/main/java/org/apache/accumulo/core/security/Credentials.java @@ -22,6 +22,7 @@ import org.apache.accumulo.core.Constants; import org.apache.accumulo.core.client.AccumuloSecurityException; import org.apache.accumulo.core.client.Connector; import org.apache.accumulo.core.client.Instance; +import org.apache.accumulo.core.client.impl.thrift.SecurityErrorCode; import org.apache.accumulo.core.client.security.tokens.AuthenticationToken; import org.apache.accumulo.core.client.security.tokens.AuthenticationToken.AuthenticationTokenSerializer; import org.apache.accumulo.core.security.thrift.TCredentials; @@ -58,7 +59,11 @@ public class Credentials { * {@link AuthenticationToken}, so this should be used just before placing on the wire, and references to it should be tightly controlled. */ public TCredentials toThrift(Instance instance) { - return new TCredentials(principal, token.getClass().getName(), ByteBuffer.wrap(AuthenticationTokenSerializer.serialize(token)), instance.getInstanceID()); + TCredentials tCreds = new TCredentials(getPrincipal(), getToken().getClass().getName(), + ByteBuffer.wrap(AuthenticationTokenSerializer.serialize(getToken())), instance.getInstanceID()); + if (getToken().isDestroyed()) + throw new RuntimeException("Token has been destroyed", new AccumuloSecurityException(getPrincipal(), SecurityErrorCode.TOKEN_EXPIRED)); + return tCreds; } /** http://git-wip-us.apache.org/repos/asf/accumulo/blob/d9ab8449/core/src/test/java/org/apache/accumulo/core/security/CredentialsTest.java ---------------------------------------------------------------------- diff --git a/core/src/test/java/org/apache/accumulo/core/security/CredentialsTest.java b/core/src/test/java/org/apache/accumulo/core/security/CredentialsTest.java index 338a330..4f8079e 100644 --- a/core/src/test/java/org/apache/accumulo/core/security/CredentialsTest.java +++ b/core/src/test/java/org/apache/accumulo/core/security/CredentialsTest.java @@ -16,13 +16,25 @@ */ package org.apache.accumulo.core.security; +import static org.junit.Assert.assertArrayEquals; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import javax.security.auth.DestroyFailedException; import org.apache.accumulo.core.Constants; +import org.apache.accumulo.core.client.AccumuloException; import org.apache.accumulo.core.client.AccumuloSecurityException; +import org.apache.accumulo.core.client.Connector; +import org.apache.accumulo.core.client.Instance; +import org.apache.accumulo.core.client.mock.MockInstance; +import org.apache.accumulo.core.client.security.SecurityErrorCode; +import org.apache.accumulo.core.client.security.tokens.AuthenticationToken.AuthenticationTokenSerializer; import org.apache.accumulo.core.client.security.tokens.NullToken; import org.apache.accumulo.core.client.security.tokens.PasswordToken; +import org.apache.accumulo.core.security.thrift.TCredentials; import org.junit.Test; /** @@ -31,6 +43,45 @@ import org.junit.Test; public class CredentialsTest { @Test + public void testToThrift() throws DestroyFailedException { + // verify thrift serialization + Credentials creds = new Credentials("test", new PasswordToken("testing")); + TCredentials tCreds = creds.toThrift(new MockInstance()); + assertEquals("test", tCreds.getPrincipal()); + assertEquals(PasswordToken.class.getName(), tCreds.getTokenClassName()); + assertArrayEquals(AuthenticationTokenSerializer.serialize(new PasswordToken("testing")), tCreds.getToken()); + + // verify that we can't serialize if it's destroyed + creds.getToken().destroy(); + try { + creds.toThrift(new MockInstance()); + fail(); + } catch (Exception e) { + assertTrue(e instanceof RuntimeException); + assertTrue(e.getCause() instanceof AccumuloSecurityException); + assertTrue(AccumuloSecurityException.class.cast(e.getCause()).getSecurityErrorCode().equals(SecurityErrorCode.TOKEN_EXPIRED)); + } + } + + @Test + public void testMockConnector() throws AccumuloException, DestroyFailedException, AccumuloSecurityException { + Instance inst = new MockInstance(); + Connector rootConnector = inst.getConnector("root", new PasswordToken()); + PasswordToken testToken = new PasswordToken("testPass"); + rootConnector.securityOperations().createLocalUser("testUser", testToken); + + assertFalse(testToken.isDestroyed()); + testToken.destroy(); + assertTrue(testToken.isDestroyed()); + try { + inst.getConnector("testUser", testToken); + fail(); + } catch (AccumuloSecurityException e) { + assertTrue(e.getSecurityErrorCode().equals(SecurityErrorCode.TOKEN_EXPIRED)); + } + } + + @Test public void testEqualsAndHashCode() { Credentials nullNullCreds = new Credentials(null, null); Credentials abcNullCreds = new Credentials("abc", new NullToken()); http://git-wip-us.apache.org/repos/asf/accumulo/blob/d9ab8449/test/src/test/java/org/apache/accumulo/test/functional/CredentialsIT.java ---------------------------------------------------------------------- diff --git a/test/src/test/java/org/apache/accumulo/test/functional/CredentialsIT.java b/test/src/test/java/org/apache/accumulo/test/functional/CredentialsIT.java new file mode 100644 index 0000000..a35a19a --- /dev/null +++ b/test/src/test/java/org/apache/accumulo/test/functional/CredentialsIT.java @@ -0,0 +1,96 @@ +/* + * 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.accumulo.test.functional; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; + +import java.util.Iterator; +import java.util.Map.Entry; + +import javax.security.auth.DestroyFailedException; + +import org.apache.accumulo.core.client.AccumuloException; +import org.apache.accumulo.core.client.AccumuloSecurityException; +import org.apache.accumulo.core.client.Connector; +import org.apache.accumulo.core.client.Scanner; +import org.apache.accumulo.core.client.TableNotFoundException; +import org.apache.accumulo.core.client.security.SecurityErrorCode; +import org.apache.accumulo.core.client.security.tokens.PasswordToken; +import org.apache.accumulo.core.data.Key; +import org.apache.accumulo.core.data.Value; +import org.apache.accumulo.core.metadata.MetadataTable; +import org.apache.accumulo.core.security.Authorizations; +import org.apache.commons.codec.binary.Base64; +import org.junit.After; +import org.junit.Before; +import org.junit.Test; + +/** + * + */ +public class CredentialsIT extends SimpleMacIT { + + private static final String username = CredentialsIT.class.getSimpleName(); + private static final String password = Base64.encodeBase64String(username.getBytes()); + + @Before + public void createLocalUser() throws AccumuloException, AccumuloSecurityException { + getConnector().securityOperations().createLocalUser(username, new PasswordToken(password)); + } + + @After + public void deleteLocalUser() throws AccumuloException, AccumuloSecurityException { + getConnector().securityOperations().dropLocalUser(username); + } + + @Test + public void testConnectorWithDestroyedToken() throws DestroyFailedException, AccumuloException { + PasswordToken token = new PasswordToken(password); + assertFalse(token.isDestroyed()); + token.destroy(); + assertTrue(token.isDestroyed()); + try { + getConnector().getInstance().getConnector("localUser", token); + fail(); + } catch (AccumuloSecurityException e) { + assertTrue(e.getSecurityErrorCode().equals(SecurityErrorCode.TOKEN_EXPIRED)); + } + } + + @Test + public void testDestroyTokenBeforeRPC() throws AccumuloException, DestroyFailedException, AccumuloSecurityException, TableNotFoundException { + PasswordToken token = new PasswordToken(password); + Connector userConnector = getConnector().getInstance().getConnector(username, token); + Scanner scanner = userConnector.createScanner(MetadataTable.NAME, Authorizations.EMPTY); + assertFalse(token.isDestroyed()); + token.destroy(); + assertTrue(token.isDestroyed()); + try { + Iterator<Entry<Key,Value>> iter = scanner.iterator(); + while (iter.hasNext()) + fail(); + fail(); + } catch (Exception e) { + assertTrue(e instanceof RuntimeException); + assertTrue(e.getCause() instanceof AccumuloSecurityException); + assertTrue(AccumuloSecurityException.class.cast(e.getCause()).getSecurityErrorCode().equals(SecurityErrorCode.TOKEN_EXPIRED)); + } + } + +}
