From ecf67df891d31b43acb45a65743c97976913b3ca Mon Sep 17 00:00:00 2001 From: Cam McKenzie Date: Thu, 23 Jul 2015 13:38:37 +1000 Subject: [PATCH 1/2] CURATOR-228 - Modified the background callback to explicitly handle the NOAUTH case. This will now log a warning and set a flag indicating that an auth failure has occured. --- .../nodes/PersistentEphemeralNode.java | 14 +++++++ .../nodes/TestPersistentEphemeralNode.java | 39 +++++++++++++++++++ 2 files changed, 53 insertions(+) diff --git a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java index f50dca48b7..35e18a53d7 100644 --- a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java +++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java @@ -41,6 +41,7 @@ import java.util.Arrays; import java.util.concurrent.CountDownLatch; import java.util.concurrent.TimeUnit; +import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import org.apache.curator.utils.PathUtils; @@ -65,6 +66,7 @@ public class PersistentEphemeralNode implements Closeable private final Mode mode; private final AtomicReference data = new AtomicReference(); private final AtomicReference state = new AtomicReference(State.LATENT); + private final AtomicBoolean authFailure = new AtomicBoolean(false); private final BackgroundCallback backgroundCallback; private final Watcher watcher = new Watcher() { @@ -233,8 +235,15 @@ else if ( event.getResultCode() == KeeperException.Code.OK.intValue() ) { path = event.getName(); } + else if ( event.getResultCode() == KeeperException.Code.NOAUTH.intValue() ) + { + log.warn("Client does not have authorisation to write ephemeral node at path {}", path); + authFailure.set(true); + return; + } if ( path != null ) { + authFailure.set(false); nodePath.set(path); watchNode(); @@ -406,4 +415,9 @@ private boolean isActive() { return (state.get() == State.STARTED); } + + public boolean isAuthFailure() + { + return authFailure.get(); + } } \ No newline at end of file diff --git a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java index 34620ff978..b199872656 100644 --- a/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java +++ b/curator-recipes/src/test/java/org/apache/curator/framework/recipes/nodes/TestPersistentEphemeralNode.java @@ -35,7 +35,9 @@ import org.apache.zookeeper.CreateMode; import org.apache.zookeeper.WatchedEvent; import org.apache.zookeeper.Watcher; +import org.apache.zookeeper.ZooDefs; import org.apache.zookeeper.Watcher.Event.EventType; +import org.apache.zookeeper.data.ACL; import org.apache.zookeeper.data.Stat; import org.testng.Assert; import org.testng.annotations.AfterMethod; @@ -572,6 +574,43 @@ public void testProtected() throws Exception node.close(); } } + + @Test + public void testNoWritePermission() throws Exception + { + CuratorFrameworkFactory.Builder builder = CuratorFrameworkFactory.builder(); + CuratorFramework client = builder + .connectString(server.getConnectString()) + .authorization("digest", "me1:pass1".getBytes()) + .retryPolicy(new RetryOneTime(1)) + .build(); + client.start(); + + ACL acl = new ACL(ZooDefs.Perms.WRITE, ZooDefs.Ids.AUTH_IDS); + List aclList = Lists.newArrayList(acl); + client.create().withACL(aclList).forPath(DIR, new byte[0]); + client.close(); + + PersistentEphemeralNode node = null; + try { + //New client without authentication + client = newCurator(); + + node = new PersistentEphemeralNode(client, PersistentEphemeralNode.Mode.EPHEMERAL, PATH, + new byte[0]); + node.start(); + + node.waitForInitialCreate(timing.seconds(), TimeUnit.SECONDS); + assertNodeDoesNotExist(client, PATH); + assertTrue(node.isAuthFailure()); + } finally { + if(node != null) { + node.close(); + } + + client.close(); + } + } private void assertNodeExists(CuratorFramework curator, String path) throws Exception { From cff86ead3385cf9dfd74b966906d9b3213bebf87 Mon Sep 17 00:00:00 2001 From: Cam McKenzie Date: Thu, 23 Jul 2015 15:59:13 +1000 Subject: [PATCH 2/2] CURATOR-228 - Remove public access from the isAuthFailure method. --- .../framework/recipes/nodes/PersistentEphemeralNode.java | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java index 35e18a53d7..11568c1a0f 100644 --- a/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java +++ b/curator-recipes/src/main/java/org/apache/curator/framework/recipes/nodes/PersistentEphemeralNode.java @@ -19,6 +19,7 @@ package org.apache.curator.framework.recipes.nodes; +import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Preconditions; import org.apache.curator.framework.CuratorFramework; @@ -416,7 +417,8 @@ private boolean isActive() return (state.get() == State.STARTED); } - public boolean isAuthFailure() + @VisibleForTesting + boolean isAuthFailure() { return authFailure.get(); }