You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@zookeeper.apache.org by sy...@apache.org on 2020/11/02 16:58:47 UTC
[zookeeper] branch master updated: ZOOKEEPER-3696: Support
alternative algorithms for ACL digest
This is an automated email from the ASF dual-hosted git repository.
symat pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zookeeper.git
The following commit(s) were added to refs/heads/master by this push:
new 392846c ZOOKEEPER-3696: Support alternative algorithms for ACL digest
392846c is described below
commit 392846c534c51a57aa678691d411ad7d8d68e29a
Author: maoling <ma...@sina.com>
AuthorDate: Mon Nov 2 16:58:08 2020 +0000
ZOOKEEPER-3696: Support alternative algorithms for ACL digest
- [SHA1](https://shattered.io/) can be cracked now and it's not safe enough to use it, `SHA2` shares the the same algorithm idea with `SHA1`, its broken would be only a matter of time, so they created `SHA3` which's safe up to now.
- The default value is: `SHA1` which will be deprecated in the future for security issues. Set this property the same value in all the servers.
- How to support other more algorithms?
- modify the `java.security` configuration file under `$JAVA_HOME/jre/lib/security/java.security` by specifying:
`security.provider.<n>=<provider class name>`.
```
For example:
set zookeeper.DigestAuthenticationProvider.digestAlg=RipeMD160
security.provider.3=org.bouncycastle.jce.provider.BouncyCastleProvider
```
- copy the jar file to `$JAVA_HOME/jre/lib/ext/`.
```
For example:
copy bcprov-jdk15on-1.60.jar to $JAVA_HOME/jre/lib/ext/
```
- For the same digest algorithm and input, the output of digest is the constant. You can use some online tools to play with it. Some UTs had covered it.
- The unit cases have tested three algorithms: `SHA1`, `SHA-256`, `SHA3-256`(other algorithms share the same principle, so ignore them), and I also do a manual test to `RipeMD160`
- For the invalid algorithm parameter
```
Caused by: java.lang.RuntimeException: don't support this ACL digest algorithm: SHA3-996 in the current environment
at org.apache.zookeeper.server.auth.DigestAuthenticationProvider.<clinit>(DigestAuthenticationProvider.java:52)
... 6 more
```
- How to migrate from one digest algorithm to another? For example: migrate from SHA1 to SHA3
```
# Before I have SHA1 for digest
superDigest=super:D/InIHSb7yEEbrWz8b9l71RjZJU=" //super:test
[zk: 127.0.0.1:2180(CONNECTED) 0] addauth digest username1:password1
[zk: 127.0.0.1:2180(CONNECTED) 2] setAcl /myapp-1 auth:username1:password1:crwad
# After I transfer to SHA3, you will get Auth Exception when getData of a
znode which already had a digest auth of old algorithm.
Step ONE: Regenerate `superDigest` when migrating to new algorithm which is always a good practice for users to survive from any uncomfortable auth issue.
reset my superDigest to super:cRy/KPYuDpW/dtsepniTMpuiuupnWgdU9txltIfv3hA=
[zk: 127.0.0.1:2180(CONNECTED) 0] addauth digest super:test
[zk: 127.0.0.1:2180(CONNECTED) 1] get /myapp-1
null
Step TWO: re-setACl for that znode.
[zk: 127.0.0.1:2180(CONNECTED) 0] addauth digest super:test
[zk: 127.0.0.1:2180(CONNECTED) 1] addauth digest username1:password1
# sometime use setAcl -R to setAcl recursively or you can also set ACL to 'world,'anyone
(open to anyone)
[zk: 127.0.0.1:2180(CONNECTED) 2] setAcl /myapp-1 auth:username1:password1:crwad
```
- [TODO]: `ZOOKEEPER-3976: write a script to encapsulate DigestAuthenticationProvider#main as a tool to generate the digest with the algorithm users appoint`
- more details in the [ZOOKEEPER-3696](https://issues.apache.org/jira/browse/ZOOKEEPER-3696)
Author: maoling <ma...@sina.com>
Reviewers: Enrico Olivelli <eo...@apache.org>, Andor Molnar <an...@apache.org>, Mate Szalay-Beko <sy...@apache.org>
This patch had conflicts when merged, resolved by
Committer: Mate Szalay-Beko <sy...@apache.org>
Closes #1318 from maoling/ZOOKEEPER-3696
---
.../src/main/resources/markdown/zookeeperAdmin.md | 27 +++++
.../zookeeper/server/ZooKeeperServerMain.java | 2 +
.../server/auth/DigestAuthenticationProvider.java | 23 ++++-
.../zookeeper/server/quorum/QuorumPeerMain.java | 2 +
.../org/apache/zookeeper/test/AuthSHA2Test.java | 89 ++++++++++++++++
.../org/apache/zookeeper/test/AuthSHA3Test.java | 89 ++++++++++++++++
.../java/org/apache/zookeeper/test/AuthTest.java | 113 ++++++++++++++++++++-
7 files changed, 343 insertions(+), 2 deletions(-)
diff --git a/zookeeper-docs/src/main/resources/markdown/zookeeperAdmin.md b/zookeeper-docs/src/main/resources/markdown/zookeeperAdmin.md
index a3a1c6c..d6087e6 100644
--- a/zookeeper-docs/src/main/resources/markdown/zookeeperAdmin.md
+++ b/zookeeper-docs/src/main/resources/markdown/zookeeperAdmin.md
@@ -1461,6 +1461,33 @@ and [SASL authentication for ZooKeeper](https://cwiki.apache.org/confluence/disp
localhost (not over the network) or over an encrypted
connection.
+* *DigestAuthenticationProvider.digestAlg* :
+ (Java system property: **zookeeper.DigestAuthenticationProvider.digestAlg**)
+ **New in 3.7.0:**
+ Set ACL digest algorithm. The default value is: `SHA1` which will be deprecated in the future for security issues.
+ Set this property the same value in all the servers.
+
+ - How to support other more algorithms?
+ - modify the `java.security` configuration file under `$JAVA_HOME/jre/lib/security/java.security` by specifying:
+ `security.provider.<n>=<provider class name>`.
+
+ ```
+ For example:
+ set zookeeper.DigestAuthenticationProvider.digestAlg=RipeMD160
+ security.provider.3=org.bouncycastle.jce.provider.BouncyCastleProvider
+ ```
+
+ - copy the jar file to `$JAVA_HOME/jre/lib/ext/`.
+
+ ```
+ For example:
+ copy bcprov-jdk15on-1.60.jar to $JAVA_HOME/jre/lib/ext/
+ ```
+
+ - How to migrate from one digest algorithm to another?
+ - 1. Regenerate `superDigest` when migrating to new algorithm.
+ - 2. `SetAcl` for a znode which already had a digest auth of old algorithm.
+
* *X509AuthenticationProvider.superUser* :
(Java system property: **zookeeper.X509AuthenticationProvider.superUser**)
The SSL-backed way to enable a ZooKeeper ensemble
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperServerMain.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperServerMain.java
index 7ddb1de..abb4d0d 100644
--- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperServerMain.java
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/ZooKeeperServerMain.java
@@ -31,6 +31,7 @@ import org.apache.zookeeper.metrics.impl.MetricsProviderBootstrap;
import org.apache.zookeeper.server.admin.AdminServer;
import org.apache.zookeeper.server.admin.AdminServer.AdminServerException;
import org.apache.zookeeper.server.admin.AdminServerFactory;
+import org.apache.zookeeper.server.auth.ProviderRegistry;
import org.apache.zookeeper.server.persistence.FileTxnSnapLog;
import org.apache.zookeeper.server.persistence.FileTxnSnapLog.DatadirException;
import org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException;
@@ -130,6 +131,7 @@ public class ZooKeeperServerMain {
throw new IOException("Cannot boot MetricsProvider " + config.getMetricsProviderClassName(), error);
}
ServerMetrics.metricsProviderInitialized(metricsProvider);
+ ProviderRegistry.initialize();
// Note that this thread isn't going to be doing anything else,
// so rather than spawning another thread, we will just call
// run() in this thread.
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/auth/DigestAuthenticationProvider.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/auth/DigestAuthenticationProvider.java
index 573cba3..8b64154 100644
--- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/auth/DigestAuthenticationProvider.java
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/auth/DigestAuthenticationProvider.java
@@ -31,6 +31,22 @@ public class DigestAuthenticationProvider implements AuthenticationProvider {
private static final Logger LOG = LoggerFactory.getLogger(DigestAuthenticationProvider.class);
+ private static final String DEFAULT_DIGEST_ALGORITHM = "SHA1";
+
+ public static final String DIGEST_ALGORITHM_KEY = "zookeeper.DigestAuthenticationProvider.digestAlg";
+
+ private static final String DIGEST_ALGORITHM = System.getProperty(DIGEST_ALGORITHM_KEY, DEFAULT_DIGEST_ALGORITHM);
+
+ static {
+ try {
+ //sanity check, pre-check the availability of the algorithm to avoid some unexpected exceptions in the runtime
+ generateDigest(DIGEST_ALGORITHM);
+ } catch (NoSuchAlgorithmException e) {
+ throw new RuntimeException("don't support this ACL digest algorithm: " + DIGEST_ALGORITHM + " in the current environment");
+ }
+ LOG.info("ACL digest algorithm is: {}", DIGEST_ALGORITHM);
+ }
+
/** specify a command line property with key of
* "zookeeper.DigestAuthenticationProvider.superDigest"
* and value of "super:<base64encoded(SHA1(password))>" to enable
@@ -89,10 +105,15 @@ public class DigestAuthenticationProvider implements AuthenticationProvider {
public static String generateDigest(String idPassword) throws NoSuchAlgorithmException {
String[] parts = idPassword.split(":", 2);
- byte[] digest = MessageDigest.getInstance("SHA1").digest(idPassword.getBytes(UTF_8));
+ byte[] digest = digest(idPassword);
return parts[0] + ":" + base64Encode(digest);
}
+ // @VisibleForTesting
+ public static byte[] digest(String idPassword) throws NoSuchAlgorithmException {
+ return MessageDigest.getInstance(DIGEST_ALGORITHM).digest(idPassword.getBytes(UTF_8));
+ }
+
public KeeperException.Code handleAuthentication(ServerCnxn cnxn, byte[] authData) {
String id = new String(authData);
try {
diff --git a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/QuorumPeerMain.java b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/QuorumPeerMain.java
index 81140b6..76df5e4 100644
--- a/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/QuorumPeerMain.java
+++ b/zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/QuorumPeerMain.java
@@ -34,6 +34,7 @@ import org.apache.zookeeper.server.ServerMetrics;
import org.apache.zookeeper.server.ZKDatabase;
import org.apache.zookeeper.server.ZooKeeperServerMain;
import org.apache.zookeeper.server.admin.AdminServer.AdminServerException;
+import org.apache.zookeeper.server.auth.ProviderRegistry;
import org.apache.zookeeper.server.persistence.FileTxnSnapLog;
import org.apache.zookeeper.server.persistence.FileTxnSnapLog.DatadirException;
import org.apache.zookeeper.server.quorum.QuorumPeerConfig.ConfigException;
@@ -159,6 +160,7 @@ public class QuorumPeerMain {
}
try {
ServerMetrics.metricsProviderInitialized(metricsProvider);
+ ProviderRegistry.initialize();
ServerCnxnFactory cnxnFactory = null;
ServerCnxnFactory secureCnxnFactory = null;
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/AuthSHA2Test.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AuthSHA2Test.java
new file mode 100644
index 0000000..298e4fb
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AuthSHA2Test.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import java.security.NoSuchAlgorithmException;
+import java.security.Security;
+import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+public class AuthSHA2Test extends AuthTest {
+
+ @BeforeAll
+ public static void setup() {
+ // use the BouncyCastle's Provider for testing
+ Security.addProvider(new BouncyCastleProvider());
+ // password is test
+ System.setProperty(DigestAuthenticationProvider.DIGEST_ALGORITHM_KEY, DigestAlgEnum.SHA_256.getName());
+ System.setProperty("zookeeper.DigestAuthenticationProvider.superDigest", "super:wjySwxg860UATFtciuZ1lpzrCHrPeov6SPu/ZD56uig=");
+ System.setProperty("zookeeper.authProvider.1", "org.apache.zookeeper.test.InvalidAuthProvider");
+ }
+
+ @AfterAll
+ public static void teardown() {
+ Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
+ System.clearProperty("zookeeper.DigestAuthenticationProvider.superDigest");
+ System.clearProperty(DigestAuthenticationProvider.DIGEST_ALGORITHM_KEY);
+ }
+
+ @Test
+ public void testBadAuthNotifiesWatch() throws Exception {
+ super.testBadAuthNotifiesWatch();
+ }
+
+ @Test
+ public void testBadAuthThenSendOtherCommands() throws Exception {
+ super.testBadAuthThenSendOtherCommands();
+ }
+
+ @Test
+ public void testSuper() throws Exception {
+ super.testSuper();
+ }
+
+ @Test
+ public void testSuperACL() throws Exception {
+ super.testSuperACL();
+ }
+
+ @Test
+ public void testOrdinaryACL() throws Exception {
+ super.testOrdinaryACL();
+ }
+
+ @Test
+ public void testGenerateDigest() throws NoSuchAlgorithmException {
+ assertEquals("super:wjySwxg860UATFtciuZ1lpzrCHrPeov6SPu/ZD56uig=", DigestAuthenticationProvider.generateDigest("super:test"));
+ assertEquals("super:Ie58Fw6KA4ucTEDj23imIltKrXNDxQg8Rwtu0biQFcU=", DigestAuthenticationProvider.generateDigest("super:zookeeper"));
+ assertEquals("super:rVOiTPnqEqlpIRXqSoE6+7h6SzbHUrfAe34i8n/gmRU=", DigestAuthenticationProvider.generateDigest(("super:foo")));
+ assertEquals("super:vs70GBagNcqIhGR4R6rXP8E3lvJPYhzMpAMx8ghbTUk=", DigestAuthenticationProvider.generateDigest(("super:bar")));
+ }
+
+ @Test
+ public void testDigest() throws NoSuchAlgorithmException {
+ assertEquals("9f86d081884c7d659a2feaa0c55ad015a3bf4f1b2b0b822cd15d6c15b0f00a08", getGeneratedDigestStr(DigestAuthenticationProvider.digest("test")));
+ assertEquals("456831beef3fc1500939995d7369695f48642664a02d5eab9d807592a08b2384", getGeneratedDigestStr(DigestAuthenticationProvider.digest("zookeeper")));
+ assertEquals("2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae", getGeneratedDigestStr(DigestAuthenticationProvider.digest(("foo"))));
+ assertEquals("fcde2b2edba56bf408601fb721fe9b5c338d10ee429ea04fae5511b68fbf8fb9", getGeneratedDigestStr(DigestAuthenticationProvider.digest(("bar"))));
+ }
+}
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/AuthSHA3Test.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AuthSHA3Test.java
new file mode 100644
index 0000000..38b070f
--- /dev/null
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AuthSHA3Test.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.zookeeper.test;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import java.security.NoSuchAlgorithmException;
+import java.security.Security;
+import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
+import org.bouncycastle.jce.provider.BouncyCastleProvider;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+
+public class AuthSHA3Test extends AuthTest {
+
+ @BeforeAll
+ public static void setup() {
+ // use the BouncyCastle's Provider for testing
+ Security.addProvider(new BouncyCastleProvider());
+ // password is test
+ System.setProperty(DigestAuthenticationProvider.DIGEST_ALGORITHM_KEY, DigestAlgEnum.SHA3_256.getName());
+ System.setProperty("zookeeper.DigestAuthenticationProvider.superDigest", "super:cRy/KPYuDpW/dtsepniTMpuiuupnWgdU9txltIfv3hA=");
+ System.setProperty("zookeeper.authProvider.1", "org.apache.zookeeper.test.InvalidAuthProvider");
+ }
+
+ @AfterAll
+ public static void teardown() {
+ Security.removeProvider(BouncyCastleProvider.PROVIDER_NAME);
+ System.clearProperty("zookeeper.DigestAuthenticationProvider.superDigest");
+ System.clearProperty(DigestAuthenticationProvider.DIGEST_ALGORITHM_KEY);
+ }
+
+ @Test
+ public void testBadAuthNotifiesWatch() throws Exception {
+ super.testBadAuthNotifiesWatch();
+ }
+
+ @Test
+ public void testBadAuthThenSendOtherCommands() throws Exception {
+ super.testBadAuthThenSendOtherCommands();
+ }
+
+ @Test
+ public void testSuper() throws Exception {
+ super.testSuper();
+ }
+
+ @Test
+ public void testSuperACL() throws Exception {
+ super.testSuperACL();
+ }
+
+ @Test
+ public void testOrdinaryACL() throws Exception {
+ super.testOrdinaryACL();
+ }
+
+ @Test
+ public void testGenerateDigest() throws NoSuchAlgorithmException {
+ assertEquals("super:cRy/KPYuDpW/dtsepniTMpuiuupnWgdU9txltIfv3hA=", DigestAuthenticationProvider.generateDigest("super:test"));
+ assertEquals("super:gM3M1QcrKC6b+h4oZ5Ixc4GTVaAsggI+AqkUaF6E1Is=", DigestAuthenticationProvider.generateDigest("super:zookeeper"));
+ assertEquals("super:2Ww7VUqTohd3lX/Vf4Nvw+GxbmOsX1p337L7Bnks4L8=", DigestAuthenticationProvider.generateDigest(("super:foo")));
+ assertEquals("super:Ft5s2Rtxr8zyz16feKiFR/8yqa6JoNEJ0In73aXojE8=", DigestAuthenticationProvider.generateDigest(("super:bar")));
+ }
+
+ @Test
+ public void testDigest() throws NoSuchAlgorithmException {
+ assertEquals("36f028580bb02cc8272a9a020f4200e346e276ae664e45ee80745574e2f5ab80", getGeneratedDigestStr(DigestAuthenticationProvider.digest("test")));
+ assertEquals("af4c1abc2deaa6edffc7ce34edeb8c03ee9a1488b64fd318ddb93b4b7f1c0746", getGeneratedDigestStr(DigestAuthenticationProvider.digest("zookeeper")));
+ assertEquals("76d3bc41c9f588f7fcd0d5bf4718f8f84b1c41b20882703100b9eb9413807c01", getGeneratedDigestStr(DigestAuthenticationProvider.digest(("foo"))));
+ assertEquals("cceefd7e0545bcf8b6d19f3b5750c8a3ee8350418877bc6fb12e32de28137355", getGeneratedDigestStr(DigestAuthenticationProvider.digest(("bar"))));
+ }
+}
diff --git a/zookeeper-server/src/test/java/org/apache/zookeeper/test/AuthTest.java b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AuthTest.java
index 211dfae..a1c95d8 100644
--- a/zookeeper-server/src/test/java/org/apache/zookeeper/test/AuthTest.java
+++ b/zookeeper-server/src/test/java/org/apache/zookeeper/test/AuthTest.java
@@ -18,8 +18,12 @@
package org.apache.zookeeper.test;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.IOException;
+import java.security.NoSuchAlgorithmException;
+import java.util.ArrayList;
+import java.util.List;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import org.apache.zookeeper.CreateMode;
@@ -27,18 +31,32 @@ import org.apache.zookeeper.KeeperException;
import org.apache.zookeeper.TestableZooKeeper;
import org.apache.zookeeper.WatchedEvent;
import org.apache.zookeeper.Watcher.Event.KeeperState;
+import org.apache.zookeeper.ZooDefs;
import org.apache.zookeeper.ZooDefs.Ids;
import org.apache.zookeeper.ZooKeeper;
+import org.apache.zookeeper.data.ACL;
+import org.apache.zookeeper.data.Id;
+import org.apache.zookeeper.server.auth.DigestAuthenticationProvider;
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.Test;
public class AuthTest extends ClientBase {
- static {
+ @BeforeAll
+ public static void setup() {
// password is test
+ // the default digestAlg is: SHA1
System.setProperty("zookeeper.DigestAuthenticationProvider.superDigest", "super:D/InIHSb7yEEbrWz8b9l71RjZJU=");
System.setProperty("zookeeper.authProvider.1", "org.apache.zookeeper.test.InvalidAuthProvider");
}
+ @AfterAll
+ public static void teardown() {
+ System.clearProperty("zookeeper.DigestAuthenticationProvider.superDigest");
+ System.clearProperty(DigestAuthenticationProvider.DIGEST_ALGORITHM_KEY);
+ }
+
private final CountDownLatch authFailed = new CountDownLatch(1);
@Override
@@ -160,4 +178,97 @@ public class AuthTest extends ClientBase {
}
}
+ @Test
+ public void testOrdinaryACL() throws Exception {
+ ZooKeeper zk = createClient();
+ try {
+ String path = "/path1";
+ zk.create(path, null, Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
+ zk.addAuthInfo("digest", "username1:password1".getBytes());
+ List<ACL> list = new ArrayList<>();
+ int perm = ZooDefs.Perms.ALL;
+ String userPassword = "username1:password1";
+ Id id = new Id("auth", userPassword);
+ list.add(new ACL(perm, id));
+ zk.setACL(path, list, -1);
+ zk.close();
+
+ zk = createClient();
+ zk.addAuthInfo("digest", "super:test".getBytes());
+ zk.getData(path, false, null);
+ zk.close();
+
+ zk = createClient();
+ try {
+ zk.getData(path, false, null);
+ fail("should have NoAuthException");
+ } catch (KeeperException.NoAuthException e) {
+ // expected
+ }
+ zk.addAuthInfo("digest", "username1:password1".getBytes());
+ zk.getData(path, false, null);
+ } finally {
+ zk.close();
+ }
+ }
+
+ @Test
+ public void testGenerateDigest() throws NoSuchAlgorithmException {
+ assertEquals("super:D/InIHSb7yEEbrWz8b9l71RjZJU=", DigestAuthenticationProvider.generateDigest("super:test"));
+ assertEquals("super:yyuhPKumRtNj4r8GnSbbwuq1vhE=", DigestAuthenticationProvider.generateDigest("super:zookeeper"));
+ assertEquals("super:t6lQTvqID/Gl5Or0n4FYE6kKP8w=", DigestAuthenticationProvider.generateDigest(("super:foo")));
+ assertEquals("super:hTdNN4QH4isoRvCrQ1Jf7REREQ4=", DigestAuthenticationProvider.generateDigest(("super:bar")));
+ }
+
+ // This test is used to check the correctness of the algorithm
+ // For the same digest algorithm and input, the output of digest hash is the constant.
+ @Test
+ public void testDigest() throws NoSuchAlgorithmException {
+ assertEquals("a94a8fe5ccb19ba61c4c0873d391e987982fbbd3", getGeneratedDigestStr(DigestAuthenticationProvider.digest("test")));
+ assertEquals("8a0444ded963cf1118dd34aa1acaafec268c654d", getGeneratedDigestStr(DigestAuthenticationProvider.digest("zookeeper")));
+ assertEquals("0beec7b5ea3f0fdbc95d0dd47f3c5bc275da8a33", getGeneratedDigestStr(DigestAuthenticationProvider.digest(("foo"))));
+ assertEquals("62cdb7020ff920e5aa642c3d4066950dd1f01f4d", getGeneratedDigestStr(DigestAuthenticationProvider.digest(("bar"))));
+ }
+
+ // this method is used to generate the digest String to help us to compare the result generated by some online tool easily
+ protected static String getGeneratedDigestStr(byte[] bytes) {
+ StringBuilder stringBuilder = new StringBuilder("");
+ if (bytes == null || bytes.length <= 0) {
+ return null;
+ }
+ for (int i = 0; i < bytes.length; i++) {
+ int v = bytes[i] & 0xFF;
+ String hv = Integer.toHexString(v);
+ if (hv.length() < 2) {
+ stringBuilder.append(0);
+ }
+ stringBuilder.append(hv);
+ }
+ return stringBuilder.toString();
+ }
+
+ public enum DigestAlgEnum {
+ SHA_1("SHA1"),
+ SHA_256("SHA-256"),
+ SHA3_256("SHA3-256");
+
+ private String name;
+
+ DigestAlgEnum(String name) {
+ this.name = name;
+ }
+
+ public String getName() {
+ return this.name;
+ }
+
+ public static List<String> getValues() {
+ List<String> digestList = new ArrayList<>();
+ for (DigestAlgEnum digest : values()) {
+ digestList.add(digest.getName());
+ }
+ return digestList;
+ }
+ }
+
}