org.apache.zookeeper。KeeperException, $InvalidACLException: KeeperErrorCode = InvalidACL for /f。

时间:2022-03-09 22:10:18

I am working with zookeeper 3.4.6, I'm using acl in order to authenticate with zookeeper server. I have my own implementation ZooKeeperSupport, it's a support for create, remove and verify znode. I am triying to create a znode using acl, but fail throwning InvalidACLException in this part of the code zooKeeperSupport.create("/f", DATA_F);

我正在与zookeeper 3.4.6合作,我正在使用acl,以通过zookeeper服务器进行身份验证。我有自己的实现ZooKeeperSupport,它支持创建、删除和验证znode。我正在尝试使用acl创建一个znode,但在代码zooKeeperSupport的这一部分中,不使用InvalidACLException。创建(“楼”,DATA_F);

I'm basing this project to do it zookeeper-acl-sample, but I want to use digest auth because use user and password

我的这个项目是基于zookeeper-acl-sample,但是我想要使用digest auth,因为使用用户和密码。

BasicMockZookeeperSecurity

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

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

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> T getData(final String path) throws Exception {
    startConnection();

    return (T) curatorClient.getData().forPath(path);
}

public <T> T create(final String path, final byte[] data) throws Exception {
    startConnection();

    return (T) curatorClient.create().forPath(path, data);
}

public <T> T create(final String path) throws Exception {
    startConnection();

    return (T) curatorClient.create().forPath(path);
}

public <T> 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<String> 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

ZookeeperSecurityUtil

public class ZookeeperSecurityUtil {

public static List<AuthInfo> getCredentialsFromSystemProperties() {
    final List<AuthInfo> 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

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

ACLProvider

public class ACLProvider implements org.apache.curator.framework.api.ACLProvider {

@Override
public List<ACL> 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<ACL> getDefaultAcl() {
    throw new NotImplementedException();
}

}

Stack

堆栈

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)

What is wrong?

是什么错了吗?

1 个解决方案

#1


1  

I have found the solution. Basically the problem is the way to create the user with password using digest schemee. According to zookeeper documentation, digest auth use an ID and password in base64 encode SHA1, apparently ACL doesn't make that automatically when you add the use to ACL so I had to do by myself.

我找到了解决方法。基本上,问题是如何使用digest schemee来创建用户的密码。根据zookeeper的文档,在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<AuthInfo> getCredentialsFromSystemProperties() {
    final List<AuthInfo> 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));
}
}

and

public class ACLProvider implements org.apache.curator.framework.api.ACLProvider {

private static final String ZK_DIGEST_SCHEME = "digest";

@Override
public List<ACL> 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<ACL> getDefaultAcl() {
    throw new NotImplementedException();
}

}

#1


1  

I have found the solution. Basically the problem is the way to create the user with password using digest schemee. According to zookeeper documentation, digest auth use an ID and password in base64 encode SHA1, apparently ACL doesn't make that automatically when you add the use to ACL so I had to do by myself.

我找到了解决方法。基本上,问题是如何使用digest schemee来创建用户的密码。根据zookeeper的文档,在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<AuthInfo> getCredentialsFromSystemProperties() {
    final List<AuthInfo> 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));
}
}

and

public class ACLProvider implements org.apache.curator.framework.api.ACLProvider {

private static final String ZK_DIGEST_SCHEME = "digest";

@Override
public List<ACL> 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<ACL> getDefaultAcl() {
    throw new NotImplementedException();
}

}