OK - I think this is the problem:
https://issues.apache.org/jira/browse/CURATOR-58
Curator is creating parent nodes without going through the ACLProvider. Please
watch CURATOR-58. If you can, please submit a patch.
-JZ
On Nov 7, 2013, at 3:51 PM, Robert Kanter <[email protected]> wrote:
> Are you sure that this is something my ACLProvider has to handle? My
> understanding is that the ACLProvider is a fairly “dumb” object that other
> code is supposed to simply use to get the ACLs to apply when creating znodes.
> The ACLProvider interface only has two methods:
> public List<ACL> getDefaultAcl();
> public List<ACL> getAclForPath(String path);
> So there’s nothing in here about protection mode.
>
> I think whatever code is changing the GUID-prefixed path into the
> originally-named path (this does happen because when I browse the znodes
> using ZKCli.sh it has “/foo” and not the prefixed one) needs to be checking
> with the ACLProvider, and its not. I tried looking around the Curator code,
> but I wasn’t able to find what does this. Do you know?
>
>
> - Robert
>
>
>
> On Thu, Nov 7, 2013 at 3:40 PM, Jordan Zimmerman <[email protected]>
> wrote:
> Yes, this is called "protection" mode. I'll paste the details from the
> Javadoc below. The TL;DR is that this is required when using
> sequential/ephemeral with ZooKeeper. So, your ACLProvider needs to be able to
> handle this.
>
> -Jordan
>
> from create().withProtection():
>
> It turns out there is an edge case that exists when creating
> sequential-ephemeral nodes. The creation can succeed on the server, but the
> server can crash before the created node name is returned to the client.
> However, the ZK session is still valid so the ephemeral node is not deleted.
> Thus, there is no way for the client to determine what node was created for
> them.
> Even without sequential-ephemeral, however, the create can succeed on the
> sever but the client (for various reasons) will not know it.
>
> Putting the create builder into protection mode works around this. The name
> of the node that is created is prefixed with a GUID. If node creation fails
> the normal retry mechanism will occur. On the retry, the parent path is first
> searched for a node that has the GUID in it. If that node is found, it is
> assumed to be the lost node that was successfully created on the first try
> and is returned to the caller.
>
> On Nov 7, 2013, at 1:13 PM, Robert Kanter <[email protected]> wrote:
>
>> I did some more investigating on this issue. It looks like when you acquire
>> a lock, it creates the path by doing:
>> ourPath =
>> client.create().creatingParentsIfNeeded().withProtection().withMode(CreateMode.EPHEMERAL_SEQUENTIAL).forPath(path);
>> When I do that manually where path is “/foo”, it actually doesn’t create
>> “/foo” yet and instead creates something like
>> "/_c_2235fc7d-f5e8-4c3a-bb24-27c610022aaa-foo0000000000”.
>>
>> From what I can tell, this has to do with the withprotection() and
>> EPHEMERAL_SEQUENTIAL mode and is to prevent some kind of problem I don’t
>> quite understand from the javadocs. In any case, I believe that something
>> eventually must rename
>> "/_c_2235fc7d-f5e8-4c3a-bb24-27c610022aaa-foo0000000000” to “/foo”. When I
>> checked, "/_c_2235fc7d-f5e8-4c3a-bb24-27c610022aaa-foo0000000000” has the
>> ACLs I set in the ACLProvider, so I’m thinking the problem must be happening
>> when the znode is renamed. I’m not sure where/when that happens, but I’d
>> guess its not using the ACLProvider and that’s why “/foo" has the default
>> ACLs.
>>
>> Do you think this is the cause? Any idea on how to fix it or workaround it?
>>
>>
>> thanks
>> - Robert
>>
>>
>>
>> On Tue, Nov 5, 2013 at 1:58 PM, Robert Kanter <[email protected]> wrote:
>> I created the below test class using JUnit. It starts a TestingServer and
>> connects to it; then it creates a path directly to verify that the custom
>> ACLProvider is being applied. Then it tries to do the same with an
>> InterProcessReadWriteLock and fails the test because its using the default
>> ACLs. I used “ip” instead of “sasl” to keep things simpler.
>>
>> I did take a quick look at the Curator code and it seemed to be using the
>> ACLProvider through the CuratorFramework when using locks, but perhaps I
>> missed something (and I’m not super familiar with the codebase).
>>
>> Please take a look; thanks!
>> - Robert
>>
>>
>> import java.util.Collections;
>> import java.util.List;
>> import junit.framework.TestCase;
>> import org.apache.curator.RetryPolicy;
>> import org.apache.curator.framework.CuratorFramework;
>> import org.apache.curator.framework.CuratorFrameworkFactory;
>> import org.apache.curator.framework.api.ACLProvider;
>> import org.apache.curator.framework.recipes.locks.InterProcessMutex;
>> import org.apache.curator.framework.recipes.locks.InterProcessReadWriteLock;
>> import org.apache.curator.retry.ExponentialBackoffRetry;
>> import org.apache.curator.test.TestingServer;
>> import org.apache.zookeeper.ZooDefs;
>> import org.apache.zookeeper.data.ACL;
>> import org.apache.zookeeper.data.Id;
>>
>> public class TestLockACLs extends TestCase {
>> private TestingServer zkServer;
>> private CuratorFramework client;
>> private final List<ACL> acls = Collections.singletonList(new
>> ACL(ZooDefs.Perms.ALL, new Id("ip", "127.0.0.1")));
>>
>> @Override
>> protected void setUp() throws Exception {
>> super.setUp();
>> zkServer = new TestingServer();
>> createClient();
>> }
>>
>> @Override
>> protected void tearDown() throws Exception {
>> super.tearDown();
>> client.close();
>> zkServer.stop();
>> zkServer.close();
>> }
>>
>> private void createClient() throws Exception {
>> RetryPolicy retryPolicy = new ExponentialBackoffRetry(1000, 3);
>> String zkConnectionString = zkServer.getConnectString();
>> String zkNamespace = "ns";
>> client = CuratorFrameworkFactory.builder()
>> .namespace(zkNamespace)
>>
>> .connectString(zkConnectionString)
>> .retryPolicy(retryPolicy)
>> .aclProvider(new MyACLProvider())
>> .build();
>> client.start();
>> }
>>
>> public void testLockACLs() throws Exception {
>> // Create a path directly and verify that MyACLProvider is being used
>> client.create().forPath("/foo");
>> assertNotNull(client.checkExists().forPath("/foo"));
>> assertEquals(ZooDefs.Perms.ALL,
>> client.getACL().forPath("/foo").get(0).getPerms());
>> assertEquals("ip",
>> client.getACL().forPath("/foo").get(0).getId().getScheme());
>> assertEquals("127.0.0.1",
>> client.getACL().forPath("/foo").get(0).getId().getId());
>>
>> // Now try creating a lock and we'll see that it incorrectly has the
>> default world ACLs
>> // and doesn't seem to be using MyACLProvider
>> InterProcessReadWriteLock lock = new
>> InterProcessReadWriteLock(client, "/bar");
>> InterProcessMutex writeLock = lock.writeLock();
>> writeLock.acquire();
>> assertNotNull(client.checkExists().forPath("/bar"));
>> assertEquals(ZooDefs.Perms.ALL,
>> client.getACL().forPath("/bar").get(0).getPerms());
>> assertEquals("ip",
>> client.getACL().forPath("/bar").get(0).getId().getScheme());
>> assertEquals("127.0.0.1",
>> client.getACL().forPath("/bar").get(0).getId().getId());
>> }
>>
>> public class MyACLProvider implements ACLProvider {
>>
>> @Override
>> public List<ACL> getDefaultAcl() {
>> return acls;
>> }
>>
>> @Override
>> public List<ACL> getAclForPath(String path) {
>> return acls;
>> }
>> }
>> }
>>
>>
>> On Mon, Nov 4, 2013 at 6:10 PM, Jordan Zimmerman
>> <[email protected]> wrote:
>> The ACLProvider should be called for every node created. It’s not getting
>> called? Can you produce a test that shows this?
>>
>> -Jordan
>>
>> On Nov 4, 2013, at 5:57 PM, Robert Kanter <[email protected]> wrote:
>>
>>> I have everything working now except for one thing:
>>> The ACLProvider doesn’t seem to be used for the locks (Curator’s
>>> InterProcessReadWriteLock); they are always created with the default fully
>>> open ACLs. I know the ACLProvider is correct now because the service
>>> discovery is using it and znodes created by it have the correct ACLs.
>>> InterProcessReadWriteLock’s constructor takes in the CuratorFramework
>>> object, which has the ACLProvider set.
>>>
>>> Any ideas?
>>> This sounds like it could be a Curator bug :(
>>> I’m not familiar with Curator’s codebase, but I’ll try to take a look and
>>> see if I can figure it out.
>>>
>>> thanks
>>> - Robert
>>>
>>>
>>>
>>> On Mon, Nov 4, 2013 at 1:09 PM, Robert Kanter <[email protected]> wrote:
>>> I don’t have it 100% working yet, but I’ve figured out a lot more, so I
>>> thought I’d share in case anyone else runs into this:
>>>
>>> The ZooDefs.Ids.CREATOR_ALL_ACL predefined ACL that I was trying to use is
>>> for the “auth” scheme. For SASL/Kerberos, we want “sasl”. The javadoc for
>>> the predefined one wasn’t very clear on that; I had to look at the code.
>>> Using this is working:
>>> Collections.singletonList(new ACL(Perms.ALL, new Id("sasl", principal)));
>>>
>>> I was also able to find answers to the three questions I asked:
>>> 1) Yes; looking through the code, its definitely grabbing the ACLProvider
>>> and using it.
>>> 2) Yes; I think the only way to do this is to recursively travel through
>>> the znodes under /oozie and apply the ACL on starting up Oozie. We should
>>> only have to do this if previously it was setup without security and has
>>> since been reconfigured to use security; so we should only have to do this
>>> once. I can probably have a znode as a flag that states if everything has
>>> ACLs or not to make it more efficient
>>> 3) It doesn’t look like it; I’ll have to get the ZK client and do it from
>>> outside Curator
>>>
>>>
>>> - Robert
>>>
>>>
>>> On Mon, Oct 28, 2013 at 5:47 PM, Jordan Zimmerman
>>> <[email protected]> wrote:
>>> I don’t have any experience with this. Curator doesn’t do much - it sets up
>>> the ACL as the CLI options dictate. I do know that you also have to do work
>>> on the server side to make this work.
>>>
>>> -JZ
>>>
>>> On Oct 24, 2013, at 4:58 PM, Robert Kanter <[email protected]> wrote:
>>>
>>>> Hi,
>>>>
>>>> Is there any documentation on using an ACLProvider and/or Kerberos?
>>>>
>>>> From what I gathered at various sites, to use Kerberos, all I have to do
>>>> is set the following properties before building the CuratorFramework
>>>> client:
>>>> System.setProperty("java.security.auth.login.config",
>>>> "/path/to/jaasConfFile");
>>>> System.setProperty("zookeeper.authProvider.1","org.apache.zookeeper.server.auth.SASLAuthenticationProvider");
>>>> System.setProperty(ZooKeeperSaslClient.LOGIN_CONTEXT_NAME_KEY, "Client");
>>>> Looking at the logs for the client and server, this appears to be working
>>>> properly and my program is connecting to ZooKeeper using Kerberos.
>>>>
>>>> The problem I'm having is with the ACLs.
>>>>
>>>> I'd like to set the ACLs so that only the Kerberos user running the
>>>> program can do anything. From what I can tell, if I specify an
>>>> ACLProvider, then Curator will automatically use it for setting ACLs on
>>>> all paths. So, an ACLProvider like the following should do what I want:
>>>> public class CreatorACLProvider implements ACLProvider {
>>>> @Override
>>>> public List<ACL> getDefaultAcl() {
>>>> return ZooDefs.Ids.CREATOR_ALL_ACL;
>>>> }
>>>> @Override
>>>> public List<ACL> getAclForPath(String path) {
>>>> return ZooDefs.Ids.CREATOR_ALL_ACL;
>>>> }
>>>> }
>>>> Then I would just do this:
>>>> client = CuratorFrameworkFactory.builder()
>>>> .namespace(zkNamespace)
>>>> .connectString(zkConnectionString)
>>>> .retryPolicy(retryPolicy)
>>>> .aclProvider(new CreatorACLProvider())
>>>> .build();
>>>> client.start();
>>>>
>>>> However, this doesn't seem to be working. The zkcli returns this (on a
>>>> newly created znode):
>>>> [zk: localhost:2181(CONNECTED) 8] getAcl
>>>> /oozie/locks/0000000-131024162150146-oozie-oozi-W
>>>> 'world,'anyone
>>>> : Cdr.
>>>> Is there something that I missed?
>>>>
>>>> A few other questions:
>>>> 1) Will the ACLProvider cause the ACLs to be applied to znodes created by
>>>> the Curator recipes? (e.g. InterProcessReadWriteLock, ServiceDiscovery,
>>>> etc). If not, then how should I go about setting the ACLs for these
>>>> znodes?
>>>> 2) I'm guessing that the ACLProvider is only applied when creating the
>>>> znode, right; so existing znodes from before I added the ACLProvider won't
>>>> have the ACLs I want, right? What would be the best way to apply the ACLs
>>>> to any existing znodes that don't have it set? (My goal is to have all
>>>> znodes under /oozie have the CREATOR_ALL_ACL)
>>>> 3) Is there a way to set the ACLs on the namespace itself (i.e. /oozie)?
>>>> The methods that take a path (and automatically prepend the namespace)
>>>> don't allow simply "/", so it seems like I'd have to use the ZooKeeper
>>>> client directly to set ACLs manually on the namespace. Or would simply
>>>> passing an empty string "" work?
>>>>
>>>> thanks
>>>> - Robert
>>>>
>>>
>>>
>>>
>>
>>
>>
>
>