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 TestingServerand >> 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<http://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 >>>>> >>>>> >>>>> >>>> >>> >>> >> > >
