org.apache.zookeeper.KeeperException $ InvalidACLException:KeeperErrorCode = / f的InvalidACL

我正在使用zookeeper 3.4.6,我正在使用acl以便使用zookeeper服务器进行身份validation。 我有自己的实现ZooKeeperSupport ,它支持创建,删除和validationznode。 我正在尝试使用acl创建一个znode ,但在代码zooKeeperSupport.create("/f", DATA_F);这一部分中失败抛出InvalidACLException zooKeeperSupport.create("/f", DATA_F);

我基于这个项目来做zookeeper-acl-sample ,但我想使用digest auth因为使用userpassword

BasicMockZookeeperSecurity

 public class BasicMockZookeeperSecurity { @Resource (name = "zooKeeperSupportFactory") protected ZooKeeperSupportFactory zooKeeperSupportFactory; public static final byte[] DATA_F = "data for znode /f".getBytes(Charsets.UTF_8); public static final byte[] DATA_B = "data for znode /b".getBytes(Charsets.UTF_8); @Before public void setup() throws Exception { System.setProperty("curator-dont-log-connection-problems", "true"); System.setProperty("zookeeper.security.user", "user"); System.setProperty("zookeeper.security.password", "pass"); System.setProperty("zookeeper.authProvider.1","com.equifax.product.fraud.common.zookeeper.security.CustomUserAuthenticationProvider"); zooKeeperSupport = CuratorFrameworkFactory.builder().connectString(connectionPath).retryPolicy(retryPolicy).aclProvider(new ACLProvider()).build(); zooKeeperSupport.create("/f", DATA_F); zooKeeperSupport.create("/b", DATA_B); } 

}

ZookeeperSecurtyTest

 public class ZookeeperSecurtyTest extends BasicMockZookeeperSecurity { @Test public void securityTester() throws Exception { final CuratorFramework curatorFramework = CuratorFrameworkFactory.builder().connectString(connectionPath).retryPolicy(retryPolicy).aclProvider(new ACLProvider()).authorization(ZookeeperSecurityUtil.getCredentialsFromSystemProperties()).build(); curatorFramework.getData().forPath("/f"); } @After public void teardown() throws Exception { System.clearProperty("zookeeeper.authProvider.1"); System.clearProperty("zookeeper.security.user"); System.clearProperty("zookeeper.security.password"); } 

}

ZooKeeperSupport

 @SuppressWarnings ("unchecked") public class ZooKeeperSupport implements AutoCloseable { private CuratorFramework curatorClient; private Builder builder; public ZooKeeperSupport(final Builder builder) { this.setBuilder(builder); this.curatorClient = builder.build(); } public  T getData(final String path) throws Exception { startConnection(); return (T) curatorClient.getData().forPath(path); } public  T create(final String path, final byte[] data) throws Exception { startConnection(); return (T) curatorClient.create().forPath(path, data); } public  T create(final String path) throws Exception { startConnection(); return (T) curatorClient.create().forPath(path); } public  T delete(final String path) throws Exception { startConnection(); return (T) curatorClient.delete().forPath(path); } public boolean exists(final String path) throws Exception { startConnection(); final Stat stat = curatorClient.checkExists().forPath(StringUtils.trim(path)); return stat != null ? true : false; } public void startConnection() { if (curatorClient.getState() == CuratorFrameworkState.LATENT) { curatorClient.start(); } } public List getChildrenNames(final String path) throws Exception { startConnection(); return curatorClient.getChildren().forPath(path); } @Override public void close() throws Exception { curatorClient.close(); curatorClient = null; } public Builder getBuilder() { return builder; } public void setBuilder(final Builder builder) { this.builder = builder; } public CuratorFramework getCuratorClient() { return curatorClient; } public void setCuratorClient(final CuratorFramework curatorClient) { this.curatorClient = curatorClient; } 

}

ZookeeperSecurityUtil

 public class ZookeeperSecurityUtil { public static List getCredentialsFromSystemProperties() { final List authInfo = new ArrayList(); final String user = System.getProperty("zookeeper.security.user"); final String password = System.getProperty("zookeeper.security.password"); authInfo.add(new AuthInfo("digest", new String(user + ":" + password).getBytes(Charsets.UTF_8))); return authInfo; } } 

CustomUserAuthenticationProvider

 public class CustomUserAuthenticationProvider implements AuthenticationProvider { @Override public String getScheme() { return "digest"; } @Override public Code handleAuthentication(final ServerCnxn cnxn, final byte[] authData) { final String userName = new String(authData, Charsets.UTF_8); if (StringUtils.isNotBlank(userName)) { cnxn.addAuthInfo(new Id(getScheme(), userName)); return Code.OK; } return Code.AUTHFAILED; } @Override public boolean isAuthenticated() { return true; } @Override public boolean isValid(final String arg0) { return true; } @Override public boolean matches(final String id, final String aclExpr) { if (Strings.isNullOrEmpty(id) || Strings.isNullOrEmpty(aclExpr)) { return false; } return id.charAt(0) == aclExpr.charAt(0); } } 

ACLProvider

 public class ACLProvider implements org.apache.curator.framework.api.ACLProvider { @Override public List getAclForPath(final String path) { final String firstLetter = String.valueOf(path.charAt(1)); final Id FIRST_USER_LETTER = new Id("digest", firstLetter); final ACL acl = new ACL(Perms.ALL, FIRST_USER_LETTER); return Collections.singletonList(acl); } @Override public List getDefaultAcl() { throw new NotImplementedException(); } } 

 org.apache.zookeeper.KeeperException$InvalidACLException: KeeperErrorCode = InvalidACL for /f at org.apache.zookeeper.KeeperException.create(KeeperException.java:121) at org.apache.zookeeper.KeeperException.create(KeeperException.java:51) at org.apache.zookeeper.ZooKeeper.create(ZooKeeper.java:783) at org.apache.curator.framework.imps.CreateBuilderImpl$11.call(CreateBuilderImpl.java:696) at org.apache.curator.framework.imps.CreateBuilderImpl$11.call(CreateBuilderImpl.java:679) at org.apache.curator.RetryLoop.callWithRetry(RetryLoop.java:107) at org.apache.curator.framework.imps.CreateBuilderImpl.pathInForeground(CreateBuilderImpl.java:676) at org.apache.curator.framework.imps.CreateBuilderImpl.protectedPathInForeground(CreateBuilderImpl.java:453) at org.apache.curator.framework.imps.CreateBuilderImpl.forPath(CreateBuilderImpl.java:443) at org.apache.curator.framework.imps.CreateBuilderImpl.forPath(CreateBuilderImpl.java:44) at com.equifax.product.fraud.common.zookeeper.support.ZooKeeperSupport.create(ZooKeeperSupport.java:35) at com.equifax.product.fraud.common.zookeeper.authentication.BasicMockZookeeperSecurity.setup(BasicMockZookeeperSecurity.java:40) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) at java.lang.reflect.Method.invoke(Unknown Source) at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:44) at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:15) at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:41) at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:27) at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:73) at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:31) at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82) at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:73) at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:263) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:224) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:83) at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231) at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60) at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229) at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50) at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222) at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61) at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:68) at org.junit.runners.ParentRunner.run(ParentRunner.java:292) at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:163) at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50) at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:459) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:675) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:382) at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:192) 

怎么了?

我找到了解决方案。 基本上问题是使用digest方案创建用户密码的方法。 根据zookeeper文档,digest auth在base64编码SHA1中使用ID和密码,显然ACL在将用法添加到ACL时不会自动生成,所以我必须自己做。

 public class ZookeeperSecurityUtil { private static final String SHA1 = "SHA1"; private static final String COLON = ":"; private static final String DIGEST_SCHEME = "digest"; public static List getCredentialsFromSystemProperties() { final List authInfo = new ArrayList<>(); final String user = System.getProperty("zookeeper.security.user"); final String password = System.getProperty("zookeeper.security.password"); authInfo.add(new AuthInfo(DIGEST_SCHEME, new String(user + COLON + password).getBytes(Charsets.UTF_8))); return authInfo; } public static String generateDigest(final String idPassword) throws NoSuchAlgorithmException { final String parts[] = idPassword.split(COLON, 2); final byte digest[] = MessageDigest.getInstance(SHA1).digest(idPassword.getBytes()); return parts[0] + COLON + base64Encode(digest); } private static String base64Encode(final byte byteDigest[]) { return new String(Base64.getEncoder().encode(byteDigest)); } } 

 public class ACLProvider implements org.apache.curator.framework.api.ACLProvider { private static final String ZK_DIGEST_SCHEME = "digest"; @Override public List getAclForPath(final String path) { final String user = System.getProperty("zookeeper.security.user"); final String password = System.getProperty("zookeeper.security.password"); Id zkId = null; try { zkId = new Id(ZK_DIGEST_SCHEME, ZookeeperSecurityUtil.generateDigest(user + ":" + password)); } catch(final NoSuchAlgorithmException e) { e.printStackTrace(); } final ACL acl = new ACL(Perms.ALL, zkId); return Collections.singletonList(acl); } @Override public List getDefaultAcl() { throw new NotImplementedException(); } } 
    Interesting Posts