[GitHub] zookeeper issue #680: ZOOKEEPER-3174: Quorum TLS - support reloading trust/k...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/680 @anmolnar is there anything blocking this from being merged at this point? ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/680 ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/680 ZOOKEEPER-3174: Quorum TLS - support reloading trust/key store Allow reloading SSL trust stores and key stores from disk when the files on disk change. ## Added support for reloading key/trust stores when the file on disk changes - new property `sslQuorumReloadCertFiles` which controls the behavior for reloading the key and trust store files for `QuorumX509Util`. Reloading of key and trust store for `ClientX509Util` is not in this PR but could be added easily - this allows a ZK server to keep running on a machine that uses short-lived certs that refresh frequently without having to restart the ZK process. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3174 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/680.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #680 commit cc72c083c0b70409d78da11507ca5e80e726bb69 Author: Ilya Maykov Date: 2018-10-25T01:54:06Z ZOOKEEPER-3174: Quorum TLS - support reloading trust/key store ---
[GitHub] zookeeper issue #680: ZOOKEEPER-3174: Quorum TLS - support reloading trust/k...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/680 @anmolnar removed finalizer, use explicit close() ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/680#discussion_r239641391 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java --- @@ -446,4 +458,119 @@ private void configureSSLServerSocket(SSLServerSocket sslServerSocket) { LOG.debug("Using Java8-optimized cipher suites for Java version {}", javaVersion); return DEFAULT_CIPHERS_JAVA8; } + +/** + * Enables automatic reloading of the trust store and key store files when they change on disk. + * + * @throws IOException if creating the FileChangeWatcher objects fails. + */ +public void enableCertFileReloading() throws IOException { +LOG.info("enabling cert file reloading"); +ZKConfig config = new ZKConfig(); +String keyStoreLocation = config.getProperty(sslKeystoreLocationProperty); +if (keyStoreLocation != null && !keyStoreLocation.isEmpty()) { +final Path filePath = Paths.get(keyStoreLocation).toAbsolutePath(); +Path parentPath = filePath.getParent(); +if (parentPath == null) { +throw new IOException( +"Key store path does not have a parent: " + filePath); +} +FileChangeWatcher newKeyStoreFileWatcher = new FileChangeWatcher( +parentPath, +watchEvent -> { +handleWatchEvent(filePath, watchEvent); +}); +// stop old watcher if there is one +if (keyStoreFileWatcher != null) { +keyStoreFileWatcher.stop(); +} +keyStoreFileWatcher = newKeyStoreFileWatcher; +keyStoreFileWatcher.start(); +} +String trustStoreLocation = config.getProperty(sslTruststoreLocationProperty); +if (trustStoreLocation != null && !trustStoreLocation.isEmpty()) { +final Path filePath = Paths.get(trustStoreLocation).toAbsolutePath(); +Path parentPath = filePath.getParent(); +if (parentPath == null) { +throw new IOException( +"Trust store path does not have a parent: " + filePath); +} +FileChangeWatcher newTrustStoreFileWatcher = new FileChangeWatcher( +parentPath, +watchEvent -> { +handleWatchEvent(filePath, watchEvent); +}); +// stop old watcher if there is one +if (trustStoreFileWatcher != null) { +trustStoreFileWatcher.stop(); +} +trustStoreFileWatcher = newTrustStoreFileWatcher; +trustStoreFileWatcher.start(); +} +} + +/** + * Disables automatic reloading of the trust store and key store files when they change on disk. + * Stops background threads and closes WatchService instances. + */ +public void disableCertFileReloading() { +if (keyStoreFileWatcher != null) { +keyStoreFileWatcher.stop(); +keyStoreFileWatcher = null; +} +if (trustStoreFileWatcher != null) { +trustStoreFileWatcher.stop(); +trustStoreFileWatcher = null; +} +} + +// Finalizer guardian object, see Effective Java item 7 +// TODO: finalize() is deprecated starting with Java 10. This needs to be +// replaced with an explicit shutdown call. +@SuppressWarnings("unused") +private final Object finalizerGuardian = new Object() { --- End diff -- Done. ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/680#discussion_r239593442 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/common/FileChangeWatcher.java --- @@ -0,0 +1,253 @@ +/** + * 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.common; + +import com.sun.nio.file.SensitivityWatchEventModifier; +import org.apache.zookeeper.server.ZooKeeperThread; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.file.ClosedWatchServiceException; +import java.nio.file.FileSystem; +import java.nio.file.Path; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.util.function.Consumer; + +/** + * Instances of this class can be used to watch a directory for file changes. When a file is added to, deleted from, + * or is modified in the given directory, the callback provided by the user will be called from a background thread. + * Some things to keep in mind: + * + * The callback should be thread-safe. + * Changes that happen around the time the thread is started may be missed. + * There is a delay between a file changing and the callback firing. + * The watch is not recursive - changes to subdirectories will not trigger a callback. + * + */ +public final class FileChangeWatcher { --- End diff -- I prefer to use composition over inheritance in cases where inheritance is not clearly better - it tends to avoid problems. If FileChangeWatcher extends Thread, then it will have a "is a" relationship with Thread, and can be used anywhere a Thread is used. Since it's not a generic Thread, it's not clear to me that this would be correct. But I don't feel too strongly about it. ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/680#discussion_r239593417 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java --- @@ -446,4 +458,119 @@ private void configureSSLServerSocket(SSLServerSocket sslServerSocket) { LOG.debug("Using Java8-optimized cipher suites for Java version {}", javaVersion); return DEFAULT_CIPHERS_JAVA8; } + +/** + * Enables automatic reloading of the trust store and key store files when they change on disk. + * + * @throws IOException if creating the FileChangeWatcher objects fails. + */ +public void enableCertFileReloading() throws IOException { +LOG.info("enabling cert file reloading"); +ZKConfig config = new ZKConfig(); +String keyStoreLocation = config.getProperty(sslKeystoreLocationProperty); +if (keyStoreLocation != null && !keyStoreLocation.isEmpty()) { +final Path filePath = Paths.get(keyStoreLocation).toAbsolutePath(); +Path parentPath = filePath.getParent(); +if (parentPath == null) { +throw new IOException( +"Key store path does not have a parent: " + filePath); +} +FileChangeWatcher newKeyStoreFileWatcher = new FileChangeWatcher( +parentPath, +watchEvent -> { +handleWatchEvent(filePath, watchEvent); +}); +// stop old watcher if there is one +if (keyStoreFileWatcher != null) { +keyStoreFileWatcher.stop(); +} +keyStoreFileWatcher = newKeyStoreFileWatcher; +keyStoreFileWatcher.start(); +} +String trustStoreLocation = config.getProperty(sslTruststoreLocationProperty); +if (trustStoreLocation != null && !trustStoreLocation.isEmpty()) { +final Path filePath = Paths.get(trustStoreLocation).toAbsolutePath(); +Path parentPath = filePath.getParent(); +if (parentPath == null) { +throw new IOException( +"Trust store path does not have a parent: " + filePath); +} +FileChangeWatcher newTrustStoreFileWatcher = new FileChangeWatcher( +parentPath, +watchEvent -> { +handleWatchEvent(filePath, watchEvent); +}); +// stop old watcher if there is one +if (trustStoreFileWatcher != null) { +trustStoreFileWatcher.stop(); +} +trustStoreFileWatcher = newTrustStoreFileWatcher; +trustStoreFileWatcher.start(); +} +} + +/** + * Disables automatic reloading of the trust store and key store files when they change on disk. + * Stops background threads and closes WatchService instances. + */ +public void disableCertFileReloading() { +if (keyStoreFileWatcher != null) { +keyStoreFileWatcher.stop(); +keyStoreFileWatcher = null; +} +if (trustStoreFileWatcher != null) { +trustStoreFileWatcher.stop(); +trustStoreFileWatcher = null; +} +} + +// Finalizer guardian object, see Effective Java item 7 +// TODO: finalize() is deprecated starting with Java 10. This needs to be +// replaced with an explicit shutdown call. +@SuppressWarnings("unused") +private final Object finalizerGuardian = new Object() { --- End diff -- I'm worried about forgetting to call `close()` and leaking the background threads. X509Util is created in other places besides QuorumPeer. But I'll see what I can do about it, we only need to call close() if we called `enableCertFileReloading()` so it might be ok ... ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/680#discussion_r239593458 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java --- @@ -446,4 +458,119 @@ private void configureSSLServerSocket(SSLServerSocket sslServerSocket) { LOG.debug("Using Java8-optimized cipher suites for Java version {}", javaVersion); return DEFAULT_CIPHERS_JAVA8; } + +/** + * Enables automatic reloading of the trust store and key store files when they change on disk. + * + * @throws IOException if creating the FileChangeWatcher objects fails. + */ +public void enableCertFileReloading() throws IOException { +LOG.info("enabling cert file reloading"); +ZKConfig config = new ZKConfig(); +String keyStoreLocation = config.getProperty(sslKeystoreLocationProperty); +if (keyStoreLocation != null && !keyStoreLocation.isEmpty()) { +final Path filePath = Paths.get(keyStoreLocation).toAbsolutePath(); +Path parentPath = filePath.getParent(); +if (parentPath == null) { +throw new IOException( +"Key store path does not have a parent: " + filePath); +} +FileChangeWatcher newKeyStoreFileWatcher = new FileChangeWatcher( +parentPath, +watchEvent -> { +handleWatchEvent(filePath, watchEvent); +}); +// stop old watcher if there is one +if (keyStoreFileWatcher != null) { +keyStoreFileWatcher.stop(); +} +keyStoreFileWatcher = newKeyStoreFileWatcher; +keyStoreFileWatcher.start(); +} +String trustStoreLocation = config.getProperty(sslTruststoreLocationProperty); +if (trustStoreLocation != null && !trustStoreLocation.isEmpty()) { --- End diff -- Will do. ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/680#discussion_r239593424 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java --- @@ -446,4 +458,119 @@ private void configureSSLServerSocket(SSLServerSocket sslServerSocket) { LOG.debug("Using Java8-optimized cipher suites for Java version {}", javaVersion); return DEFAULT_CIPHERS_JAVA8; } + +/** + * Enables automatic reloading of the trust store and key store files when they change on disk. + * + * @throws IOException if creating the FileChangeWatcher objects fails. + */ +public void enableCertFileReloading() throws IOException { +LOG.info("enabling cert file reloading"); +ZKConfig config = new ZKConfig(); +String keyStoreLocation = config.getProperty(sslKeystoreLocationProperty); +if (keyStoreLocation != null && !keyStoreLocation.isEmpty()) { +final Path filePath = Paths.get(keyStoreLocation).toAbsolutePath(); +Path parentPath = filePath.getParent(); +if (parentPath == null) { +throw new IOException( +"Key store path does not have a parent: " + filePath); +} +FileChangeWatcher newKeyStoreFileWatcher = new FileChangeWatcher( +parentPath, +watchEvent -> { +handleWatchEvent(filePath, watchEvent); +}); +// stop old watcher if there is one +if (keyStoreFileWatcher != null) { +keyStoreFileWatcher.stop(); +} +keyStoreFileWatcher = newKeyStoreFileWatcher; +keyStoreFileWatcher.start(); +} +String trustStoreLocation = config.getProperty(sslTruststoreLocationProperty); +if (trustStoreLocation != null && !trustStoreLocation.isEmpty()) { +final Path filePath = Paths.get(trustStoreLocation).toAbsolutePath(); +Path parentPath = filePath.getParent(); +if (parentPath == null) { +throw new IOException( +"Trust store path does not have a parent: " + filePath); +} +FileChangeWatcher newTrustStoreFileWatcher = new FileChangeWatcher( +parentPath, +watchEvent -> { +handleWatchEvent(filePath, watchEvent); +}); +// stop old watcher if there is one +if (trustStoreFileWatcher != null) { +trustStoreFileWatcher.stop(); +} +trustStoreFileWatcher = newTrustStoreFileWatcher; +trustStoreFileWatcher.start(); +} +} + +/** + * Disables automatic reloading of the trust store and key store files when they change on disk. + * Stops background threads and closes WatchService instances. + */ +public void disableCertFileReloading() { --- End diff -- Will do. ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/680 ZOOKEEPER-3174: Quorum TLS - support reloading trust/key store Allow reloading SSL trust stores and key stores from disk when the files on disk change. ## Added support for reloading key/trust stores when the file on disk changes - new property `sslQuorumReloadCertFiles` which controls the behavior for reloading the key and trust store files for `QuorumX509Util`. Reloading of key and trust store for `ClientX509Util` is not in this PR but could be added easily - this allows a ZK server to keep running on a machine that uses short-lived certs that refresh frequently without having to restart the ZK process. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3174 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/680.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #680 commit b373878e45151ea736055cd0a1cf51181a0f0e0d Author: Ilya Maykov Date: 2018-10-25T01:54:06Z ZOOKEEPER-3174: Quorum TLS - support reloading trust/key store ---
[GitHub] zookeeper pull request #710: ZOOKEEPER-3195: TLS - disable client-initiated ...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/710 ZOOKEEPER-3195: TLS - disable client-initiated renegotiation Summary: client-initiated renegotiation is insecure and is vulnerable to MITM attacks. Unfortunately, the feature is enabled in Java by default. This disables it. See https://bugs.openjdk.java.net/browse/JDK-7188658 and https://www.oracle.com/technetwork/java/javase/documentation/tlsreadme-141115.html Test Plan: manually tested by running a secure ZK server and probing the listening port with python's sslyze tool (using `sslyze --reneg ...`). Tested on Java 8, 9, 10, and 11. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3195 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/710.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #710 commit fc7f54819fa3ec618d368f73e014614e4e39ef11 Author: Ilya Maykov Date: 2018-11-20T23:30:23Z ZOOKEEPER-3195: TLS - disable client-initiated renegotiation Summary: client-initiated renegotiation is insecure and is vulnerable to MITM attacks. Unfortunately, the feature is enabled in Java by default. This disables it. See https://bugs.openjdk.java.net/browse/JDK-7188658 and https://www.oracle.com/technetwork/java/javase/documentation/tlsreadme-141115.html Test Plan: manually tested by running a secure ZK server and probing the listening port with python's sslyze tool (using `sslyze --reneg ...`). Tested on Java 8, 9, 10, and 11. Also added a unit test that verifies client-initiated renegotiation fails. ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/680 ---
[GitHub] zookeeper pull request #710: ZOOKEEPER-3195: TLS - disable client-initiated ...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/710 ---
[GitHub] zookeeper issue #680: ZOOKEEPER-3174: Quorum TLS - support reloading trust/k...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/680 @anmolnar looks like FileMonitor only exists in our fork for now and is not upstreamed yet, so never mind about that comment! I'll work with other FB engineers to unify the two classes. ---
[GitHub] zookeeper issue #680: ZOOKEEPER-3174: Quorum TLS - support reloading trust/k...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/680 @anmolnar is there anything I can do to help move this PR and #681 along? ---
[GitHub] zookeeper issue #709: ZOOKEEPER-3194: Quorum TLS - fix copy/paste bug in ZKT...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/709 @anmolnar could you merge this into master and branch-3.5? ---
[GitHub] zookeeper pull request #727: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/727 ---
[GitHub] zookeeper issue #680: ZOOKEEPER-3174: Quorum TLS - support reloading trust/k...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/680 @anmolnar I just stumbled across the FileMonitor class, which has similar functionality to my FileChangeWatcher. The main difference is that it polls for changes and sleeps the thread in between, rather than using WatchService. It also ignores mtime changes if the file contents have not changed. Maybe I should use FileMonitor and remove the FileChangeWatcher class? ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/680 ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/680 ZOOKEEPER-3174: Quorum TLS - support reloading trust/key store Allow reloading SSL trust stores and key stores from disk when the files on disk change. ## Added support for reloading key/trust stores when the file on disk changes - new property `sslQuorumReloadCertFiles` which controls the behavior for reloading the key and trust store files for `QuorumX509Util`. Reloading of key and trust store for `ClientX509Util` is not in this PR but could be added easily - this allows a ZK server to keep running on a machine that uses short-lived certs that refresh frequently without having to restart the ZK process. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3174 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/680.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #680 commit 6c492bbad6021c12f3e1bc0b57a3b35bab771696 Author: Ilya Maykov Date: 2018-10-25T01:54:06Z ZOOKEEPER-3174: Quorum TLS - support reloading trust/key store ---
[GitHub] zookeeper issue #727: ZOOKEEPER-3172: Quorum TLS - fix port unification to a...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/727 @anmolnar here is the branch-3.5 version of #679 ---
[GitHub] zookeeper pull request #727: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
GitHub user ivmaykov opened a pull request: https://github.com/apache/zookeeper/pull/727 ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades Fix numerous problems with UnifiedServerSocket, such as hanging the accept() thread when the client doesn't send any data or crashing if less than 5 bytes are read from the socket in the initial read. Re-enable the "portUnification" config option. ### Fixed networking issues/bugs in UnifiedServerSocket - don't crash the accept() thread if the client closes the connection without sending any data - don't corrupt the connection if the client sends fewer than 5 bytes for the initial read - delay the detection of TLS vs. plaintext mode until a socket stream is read from or written to. This prevents the accept() thread from getting blocked on a read() operation from the newly connected socket. - prepending 5 bytes to PrependableSocket and then trying to read >5 bytes would only return the first 5 bytes, even if more bytes were available. This is fixed. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3172-branch-3.5 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/727.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #727 commit 4a6a22f083930597b8ab3a5cb35048a6ab24813b Author: Ilya Maykov Date: 2018-10-25T01:22:24Z ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades ---
[GitHub] zookeeper issue #679: ZOOKEEPER-3172: Quorum TLS - fix port unification to a...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/679 @anmolnar renamed the tests and cleaned them up quite a bit too (the formerly-DoS tests don't actually need a background thread for the bad client socket, which simplifies things). ---
[GitHub] zookeeper issue #679: ZOOKEEPER-3172: Quorum TLS - fix port unification to a...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/679 @anmolnar put the DoS tests back in. If you decide that you're ok with keeping them, let me know what you'd like me to rename / comment. ---
[GitHub] zookeeper issue #679: ZOOKEEPER-3172: Quorum TLS - fix port unification to a...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/679 I like the old DoS tests, I'm happy to restore them. The new unit test I added can stay too. ---
[GitHub] zookeeper issue #679: ZOOKEEPER-3172: Quorum TLS - fix port unification to a...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/679 @anmolnar removed DoS tests from `UnifiedServerSocketTest.java`. Added a new unit test `UnifiedServerSocketModeDetectionTest.java` which checks that calling certain methods on the server side of a unified socket connection does not trigger mode detection. Also rebased on latest master to fix merge conflict. ---
[GitHub] zookeeper issue #679: ZOOKEEPER-3172: Quorum TLS - fix port unification to a...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/679 @anmolnar I understand your point about the DoS tests, and agree that they are not very focused and do end up testing the structure of the test code itself in (i.e. that the implementation of `UnifiedServerSocketTest$UnifiedServerThread` plays nicely with `UnifiedServerSocket`). Let me explain really briefly how that test came about, since the history behind it is missing in this discussion. Initially when I rewrote `UnifiedServerSocket` and added the `UnifiedSocket` inner class, I didn't have the `UnifiedInputStream` and `UnifiedOutputStream` inner classes. I was careful to avoid any reads inside `accept()`, and thought that was good enough. However, with this version of the code we still saw problems on our test cluster during a stress disconnect/reconnect test. Investigation showed evidence that the Leader's `accept()` thread was getting stuck, and then I found the code in `Leader$LearnerCnxAcceptor#run()` that calls `getInputStream()` on the accepted socket and wraps the result in a `BufferedInputStream`. The only way at the time to get the input stream was to resolve the type of socket (by doing a read of first 5 bytes and then TLS/plaintext mode detection), and get the real socket's input stream. My fix involved adding the `UnifiedInputStream` and `UnifiedOutputStream` inner classes, which allowed me to delay the mode detection. Now, instead of triggering mode detection at the time of `getInputStream()`, we can trigger it the first time the stream is used for I/O. I wrote the DoS test as part of the same diff, and was careful to replicate the threading behavior of `Leader$LearnerCnxAcceptor.run()` in `UnifiedServerThread`. I also verified that the new tests failed on a version of the code that didn't have the unified stream wrappers. If I remove the DoS tests, the behavior of delaying the mode detection's read to the point of first I/O operation would not be tested properly. I think that code should be tested! However, if you prefer I could probably test it in a more focused way (i.e. just test each method that's meant to be non-blocking by itself). Would that be an acceptable compromise? ---
[GitHub] zookeeper pull request #710: ZOOKEEPER-3195: TLS - disable client-initiated ...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/710#discussion_r235552846 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java --- @@ -60,6 +60,12 @@ public abstract class X509Util { private static final Logger LOG = LoggerFactory.getLogger(X509Util.class); +static { +// Client-initiated renegotiation in TLS is unsafe and +// allows MITM attacks, so we should always disable it. +System.setProperty("jdk.tls.rejectClientInitiatedRenegotiation", "true"); --- End diff -- Sure, will do ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/679 ---
[GitHub] zookeeper pull request #669: ZOOKEEPER-3152: Port ZK netty stack to netty4
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/669 ZOOKEEPER-3152: Port ZK netty stack to netty4 Summary: Ported the client connection netty stack from netty3 to netty4. This includes both the server side (NettyServerCnxn and friends) and the client side (ClientCnxnSocketNetty). Test Plan: Modified `FourLetterWordsTest` and `NettyServerCnxnTest`, plus manual testing on a regional ensemble. FB Reviewers: nixon You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3152 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/669.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #669 commit 4fb8eb6ebe69a4f9a0852624d652d0893d6ba625 Author: Ilya Maykov Date: 2018-08-31T23:26:55Z port ZK netty stack from netty3 to netty4 Summary: Ported the client connection netty stack from netty3 to netty4. This includes both the server side (NettyServerCnxn and friends) and the client side (ClientCnxnSocketNetty). Test Plan: Modified `FourLetterWordsTest` and `NettyServerCnxnTest`, plus manual testing on a regional ensemble. Reviewers: nixon, nwolchko, nedelchev Subscribers: Differential Revision: https://phabricator.intern.facebook.com/D9646262 Tasks: Tags: Blame Revision: ---
[GitHub] zookeeper pull request #669: ZOOKEEPER-3152: Port ZK netty stack to netty4
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/669 ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/679 ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades Fix numerous problems with UnifiedServerSocket, such as hanging the accept() thread when the client doesn't send any data or crashing if less than 5 bytes are read from the socket in the initial read. Re-enable the "portUnification" config option. ## Fixed networking issues/bugs in UnifiedServerSocket - don't crash the `accept()` thread if the client closes the connection without sending any data - don't corrupt the connection if the client sends fewer than 5 bytes for the initial read - delay the detection of TLS vs. plaintext mode until a socket stream is read from or written to. This prevents the `accept()` thread from getting blocked on a `read()` operation from the newly connected socket. - prepending 5 bytes to `PrependableSocket` and then trying to read >5 bytes would only return the first 5 bytes, even if more bytes were available. This is fixed. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3172 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/679.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #679 ---
[GitHub] zookeeper pull request #710: ZOOKEEPER-3195: TLS - disable client-initiated ...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/710 ZOOKEEPER-3195: TLS - disable client-initiated renegotiation Summary: client-initiated renegotiation is insecure and is vulnerable to MITM attacks. Unfortunately, the feature is enabled in Java by default. This disables it. See https://bugs.openjdk.java.net/browse/JDK-7188658 and https://www.oracle.com/technetwork/java/javase/documentation/tlsreadme-141115.html Test Plan: manually tested by running a secure ZK server and probing the listening port with python's sslyze tool (using `sslyze --reneg ...`). Tested on Java 8, 9, 10, and 11. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3195 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/710.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #710 commit 027d7d24912dc7a00d798a77196f83be06229755 Author: Ilya Maykov Date: 2018-11-20T23:30:23Z ZOOKEEPER-3195: TLS - disable client-initiated renegotiation Summary: client-initiated renegotiation is insecure and is vulnerable to MITM attacks. Unfortunately, the feature is enabled in Java by default. This disables it. See https://bugs.openjdk.java.net/browse/JDK-7188658 and https://www.oracle.com/technetwork/java/javase/documentation/tlsreadme-141115.html Test Plan: manually tested by running a secure ZK server and probing the listening port with python's sslyze tool (using `sslyze --reneg ...`). Tested on Java 8, 9, 10, and 11. ---
[GitHub] zookeeper issue #710: ZOOKEEPER-3195: TLS - disable client-initiated renegot...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/710 The jenkins failures seem to be due to unrelated flaky tests. I'll try closing/reopening the PR until it succeeds ... ---
[GitHub] zookeeper pull request #710: ZOOKEEPER-3195: TLS - disable client-initiated ...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/710 ---
[GitHub] zookeeper pull request #710: ZOOKEEPER-3195: TLS - disable client-initiated ...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/710#discussion_r235489458 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java --- @@ -60,6 +60,12 @@ public abstract class X509Util { private static final Logger LOG = LoggerFactory.getLogger(X509Util.class); +static { +// Client-initiated renegotiation in TLS is unsafe and +// allows MITM attacks, so we should always disable it. +System.setProperty("jdk.tls.rejectClientInitiatedRenegotiation", "true"); --- End diff -- I'm not sure. However, setting it to true before any SSLContext objects are created by X509Util seems to do the trick. I'm not sure if flipping it back to `false` after the server is running and sockets are created would lead to future connections allowing client-initiated renegotiation or not. I don't think it matters since we don't have a way to flip the option back to `false`. ---
[GitHub] zookeeper pull request #710: ZOOKEEPER-3195: TLS - disable client-initiated ...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/710 ZOOKEEPER-3195: TLS - disable client-initiated renegotiation Summary: client-initiated renegotiation is insecure and is vulnerable to MITM attacks. Unfortunately, the feature is enabled in Java by default. This disables it. See https://bugs.openjdk.java.net/browse/JDK-7188658 and https://www.oracle.com/technetwork/java/javase/documentation/tlsreadme-141115.html Test Plan: manually tested by running a secure ZK server and probing the listening port with python's sslyze tool (using `sslyze --reneg ...`). Tested on Java 8, 9, 10, and 11. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3195 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/710.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #710 commit 027d7d24912dc7a00d798a77196f83be06229755 Author: Ilya Maykov Date: 2018-11-20T23:30:23Z ZOOKEEPER-3195: TLS - disable client-initiated renegotiation Summary: client-initiated renegotiation is insecure and is vulnerable to MITM attacks. Unfortunately, the feature is enabled in Java by default. This disables it. See https://bugs.openjdk.java.net/browse/JDK-7188658 and https://www.oracle.com/technetwork/java/javase/documentation/tlsreadme-141115.html Test Plan: manually tested by running a secure ZK server and probing the listening port with python's sslyze tool (using `sslyze --reneg ...`). Tested on Java 8, 9, 10, and 11. ---
[GitHub] zookeeper pull request #710: ZOOKEEPER-3195: TLS - disable client-initiated ...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/710 ---
[GitHub] zookeeper pull request #709: ZOOKEEPER-3194: Quorum TLS - fix copy/paste bug...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/709 ---
[GitHub] zookeeper pull request #709: ZOOKEEPER-3194: Quorum TLS - fix copy/paste bug...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/709 ZOOKEEPER-3194: Quorum TLS - fix copy/paste bug in ZKTrustManager Fix an obvious copy/paste bug. Tested by making sure ZKTrustManagerTest still passes. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3194 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/709.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #709 commit ad6502ddc47236c4db359e1d1fa5af3a48e2684c Author: Ilya Maykov Date: 2018-11-20T23:23:28Z ZOOKEEPER-3194: Quorum TLS - fix copy/paste bug in ZKTrustManager ---
[GitHub] zookeeper pull request #710: ZOOKEEPER-3195: TLS - disable client-initiated ...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/710 ZOOKEEPER-3195: TLS - disable client-initiated renegotiation Summary: client-initiated renegotiation is insecure and is vulnerable to MITM attacks. Unfortunately, the feature is enabled in Java by default. This disables it. See https://bugs.openjdk.java.net/browse/JDK-7188658 and https://www.oracle.com/technetwork/java/javase/documentation/tlsreadme-141115.html Test Plan: manually tested by running a secure ZK server and probing the listening port with python's sslyze tool (using `sslyze --reneg ...`). Tested on Java 8, 9, 10, and 11. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3195 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/710.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #710 commit 027d7d24912dc7a00d798a77196f83be06229755 Author: Ilya Maykov Date: 2018-11-20T23:30:23Z ZOOKEEPER-3195: TLS - disable client-initiated renegotiation Summary: client-initiated renegotiation is insecure and is vulnerable to MITM attacks. Unfortunately, the feature is enabled in Java by default. This disables it. See https://bugs.openjdk.java.net/browse/JDK-7188658 and https://www.oracle.com/technetwork/java/javase/documentation/tlsreadme-141115.html Test Plan: manually tested by running a secure ZK server and probing the listening port with python's sslyze tool (using `sslyze --reneg ...`). Tested on Java 8, 9, 10, and 11. ---
[GitHub] zookeeper pull request #709: ZOOKEEPER-3194: Quorum TLS - fix copy/paste bug...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/709 ---
[GitHub] zookeeper pull request #710: ZOOKEEPER-3195: TLS - disable client-initiated ...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/710 ---
[GitHub] zookeeper pull request #709: ZOOKEEPER-3194: Quorum TLS - fix copy/paste bug...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/709 ZOOKEEPER-3194: Quorum TLS - fix copy/paste bug in ZKTrustManager Fix an obvious copy/paste bug. Tested by making sure ZKTrustManagerTest still passes. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3194 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/709.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #709 commit ad6502ddc47236c4db359e1d1fa5af3a48e2684c Author: Ilya Maykov Date: 2018-11-20T23:23:28Z ZOOKEEPER-3194: Quorum TLS - fix copy/paste bug in ZKTrustManager ---
[GitHub] zookeeper pull request #710: ZOOKEEPER-3195: TLS - disable client-initiated ...
GitHub user ivmaykov opened a pull request: https://github.com/apache/zookeeper/pull/710 ZOOKEEPER-3195: TLS - disable client-initiated renegotiation Summary: client-initiated renegotiation is insecure and is vulnerable to MITM attacks. Unfortunately, the feature is enabled in Java by default. This disables it. See https://bugs.openjdk.java.net/browse/JDK-7188658 and https://www.oracle.com/technetwork/java/javase/documentation/tlsreadme-141115.html Test Plan: manually tested by running a secure ZK server and probing the listening port with python's sslyze tool (using `sslyze --reneg ...`). Tested on Java 8, 9, 10, and 11. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3195 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/710.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #710 commit 027d7d24912dc7a00d798a77196f83be06229755 Author: Ilya Maykov Date: 2018-11-20T23:30:23Z ZOOKEEPER-3195: TLS - disable client-initiated renegotiation Summary: client-initiated renegotiation is insecure and is vulnerable to MITM attacks. Unfortunately, the feature is enabled in Java by default. This disables it. See https://bugs.openjdk.java.net/browse/JDK-7188658 and https://www.oracle.com/technetwork/java/javase/documentation/tlsreadme-141115.html Test Plan: manually tested by running a secure ZK server and probing the listening port with python's sslyze tool (using `sslyze --reneg ...`). Tested on Java 8, 9, 10, and 11. ---
[GitHub] zookeeper pull request #709: ZOOKEEPER-3194: Quorum TLS - fix copy/paste bug...
GitHub user ivmaykov opened a pull request: https://github.com/apache/zookeeper/pull/709 ZOOKEEPER-3194: Quorum TLS - fix copy/paste bug in ZKTrustManager Fix an obvious copy/paste bug. Tested by making sure ZKTrustManagerTest still passes. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3194 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/709.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #709 commit ad6502ddc47236c4db359e1d1fa5af3a48e2684c Author: Ilya Maykov Date: 2018-11-20T23:23:28Z ZOOKEEPER-3194: Quorum TLS - fix copy/paste bug in ZKTrustManager ---
[GitHub] zookeeper issue #679: ZOOKEEPER-3172: Quorum TLS - fix port unification to a...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/679 @anmolnar the benefit of the current DOS tests is to verify that certain actions on a UnifiedSocket (getting input stream, setting socket options, etc) do not trigger the blocking read for TLS / plaintext mode detection. I think there is benefit to having such tests `UnifiedServerSocketTest`, since they test behavior that's implemented in `UnifiedServerSocket.java`. What do you think? ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/680 ---
[GitHub] zookeeper pull request #681: ZOOKEEPER-3176: Quorum TLS - add SSL config opt...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/681 ZOOKEEPER-3176: Quorum TLS - add SSL config options Add SSL config options for enabled protocols and client auth mode. Improve handling of SSL config options for protocols and cipher suites - previously these came from system properties, now they can come from ZKConfig which means they are easier to isolate in tests, and now we don't need to parse system properties every time we create a secure socket. Note that this is stacked on top of #678, #679, and #680 and thus includes them. Please only consider the ZOOKEEPER-3176 commit when reviewing. Once the other PRs are merged upstream, I will rebase this so it only contains one commit. ## Added more options for ssl settings to X509Util and encapsulate them better - previously, some SSL settings came from a `ZKConfig` and others came from global `System.getProperties()`. This made it hard to isolate certain settings in tests. - now all SSL-related settings come from the `ZKConfig` object used to create the SSL context - new settings added: - `zookeeper.ssl(.quorum).enabledProtocols` - list of enabled protocols. If not set, defaults to a single-entry list with the value of `zookeeper.ssl(.quorum).protocol`. - `zookeeper.ssl(.quorum).clientAuth` - can be "NONE", "WANT", or "NEED". This controls whether the server doesn't want / allows / requires the client to present an X509 certificate. - `zookeeper.ssl(.quorum).handshakeDetectionTimeoutMillis` - timeout for the first read of 5 bytes to detect the transport mode (TLS or plaintext) of a client connection made to a `UnifiedServerSocket` You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3176 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/681.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #681 commit 367bef0980193e2761c7008844c5e9fe029d8a66 Author: Ilya Maykov Date: 2018-10-25T01:22:24Z ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades commit fd58fa45cdd76c6b4c1bb2f529ee8f6d7fff553d Author: Ilya Maykov Date: 2018-10-25T01:54:06Z ZOOKEEPER-3174: Quorum TLS - support reloading trust/key store commit d232235519e2c6e252dcac700dcc05146cea5dbc Author: Ilya Maykov Date: 2018-10-25T02:12:04Z ZOOKEEPER-3176: Quorum TLS - add SSL config options ---
[GitHub] zookeeper pull request #681: ZOOKEEPER-3176: Quorum TLS - add SSL config opt...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/681 ---
[GitHub] zookeeper issue #679: ZOOKEEPER-3172: Quorum TLS - fix port unification to a...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/679 @anmolnar use Executor and InetAddress.getLoopbackAddress() ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/679 ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades Fix numerous problems with UnifiedServerSocket, such as hanging the accept() thread when the client doesn't send any data or crashing if less than 5 bytes are read from the socket in the initial read. Re-enable the "portUnification" config option. ## Fixed networking issues/bugs in UnifiedServerSocket - don't crash the `accept()` thread if the client closes the connection without sending any data - don't corrupt the connection if the client sends fewer than 5 bytes for the initial read - delay the detection of TLS vs. plaintext mode until a socket stream is read from or written to. This prevents the `accept()` thread from getting blocked on a `read()` operation from the newly connected socket. - prepending 5 bytes to `PrependableSocket` and then trying to read >5 bytes would only return the first 5 bytes, even if more bytes were available. This is fixed. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3172 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/679.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #679 commit 367bef0980193e2761c7008844c5e9fe029d8a66 Author: Ilya Maykov Date: 2018-10-25T01:22:24Z ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/679 ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/679#discussion_r234053630 --- Diff: zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/UnifiedServerSocketTest.java --- @@ -17,156 +17,644 @@ */ package org.apache.zookeeper.server.quorum; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLSocket; + import org.apache.zookeeper.PortAssignment; import org.apache.zookeeper.client.ZKClientConfig; +import org.apache.zookeeper.common.BaseX509ParameterizedTestCase; import org.apache.zookeeper.common.ClientX509Util; -import org.apache.zookeeper.common.Time; +import org.apache.zookeeper.common.KeyStoreFileType; +import org.apache.zookeeper.common.X509Exception; +import org.apache.zookeeper.common.X509KeyType; +import org.apache.zookeeper.common.X509TestContext; import org.apache.zookeeper.common.X509Util; import org.apache.zookeeper.server.ServerCnxnFactory; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; -import javax.net.ssl.HandshakeCompletedEvent; -import javax.net.ssl.HandshakeCompletedListener; -import javax.net.ssl.SSLSocket; -import java.io.IOException; -import java.net.ConnectException; -import java.net.InetSocketAddress; -import java.net.Socket; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; +@RunWith(Parameterized.class) +public class UnifiedServerSocketTest extends BaseX509ParameterizedTestCase { -public class UnifiedServerSocketTest { +@Parameterized.Parameters +public static Collection params() { +ArrayList result = new ArrayList<>(); +int paramIndex = 0; +for (X509KeyType caKeyType : X509KeyType.values()) { +for (X509KeyType certKeyType : X509KeyType.values()) { +for (Boolean hostnameVerification : new Boolean[] { true, false }) { +result.add(new Object[]{ +caKeyType, +certKeyType, +hostnameVerification, +paramIndex++ +}); +} +} +} +return result; +} private static final int MAX_RETRIES = 5; private static final int TIMEOUT = 1000; +private static final byte[] DATA_TO_CLIENT = "hello client".getBytes(); +private static final byte[] DATA_FROM_CLIENT = "hello server".getBytes(); private X509Util x509Util; private int port; -private volatile boolean handshakeCompleted; +private InetSocketAddress localServerAddress; +private final Object handshakeCompletedLock = new Object(); +// access only inside synchronized(handshakeCompletedLock) { ... } blocks +private boolean handshakeCompleted = false; + +public UnifiedServerSocketTest( +final X509KeyType caKeyType, +final X509KeyType certKeyType, +final Boolean hostnameVerification, +final Integer paramIndex) { +super(paramIndex, () -> { +try { +return X509TestContext.newBuilder() +.setTempDir(tempDir) +.setKeyStoreKeyType(certKeyType) +.setTrustStoreKeyType(caKeyType) +.setHostnameVerification(hostnameVerification) +.build(); +} catch (Exception e) { +throw new RuntimeException(e); +} +}); +} @Before public void setUp() throws Exception { -handshakeCompleted = false; - port = PortAssignment.unique(); +localServerAddress = new InetSocketAddress("localhost", port); -String testDataPath = System.getProperty("test.data.dir", "build/test/data"); System.setProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY, "org.apache.zookeeper.server.NettyServerCnxnFactory"); System.setProperty(ZKClientConfig.ZOOKE
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/679#discussion_r234053611 --- Diff: zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/UnifiedServerSocketTest.java --- @@ -17,156 +17,644 @@ */ package org.apache.zookeeper.server.quorum; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLSocket; + import org.apache.zookeeper.PortAssignment; import org.apache.zookeeper.client.ZKClientConfig; +import org.apache.zookeeper.common.BaseX509ParameterizedTestCase; import org.apache.zookeeper.common.ClientX509Util; -import org.apache.zookeeper.common.Time; +import org.apache.zookeeper.common.KeyStoreFileType; +import org.apache.zookeeper.common.X509Exception; +import org.apache.zookeeper.common.X509KeyType; +import org.apache.zookeeper.common.X509TestContext; import org.apache.zookeeper.common.X509Util; import org.apache.zookeeper.server.ServerCnxnFactory; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; -import javax.net.ssl.HandshakeCompletedEvent; -import javax.net.ssl.HandshakeCompletedListener; -import javax.net.ssl.SSLSocket; -import java.io.IOException; -import java.net.ConnectException; -import java.net.InetSocketAddress; -import java.net.Socket; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; +@RunWith(Parameterized.class) +public class UnifiedServerSocketTest extends BaseX509ParameterizedTestCase { -public class UnifiedServerSocketTest { +@Parameterized.Parameters +public static Collection params() { +ArrayList result = new ArrayList<>(); +int paramIndex = 0; +for (X509KeyType caKeyType : X509KeyType.values()) { +for (X509KeyType certKeyType : X509KeyType.values()) { +for (Boolean hostnameVerification : new Boolean[] { true, false }) { +result.add(new Object[]{ +caKeyType, +certKeyType, +hostnameVerification, +paramIndex++ +}); +} +} +} +return result; +} private static final int MAX_RETRIES = 5; private static final int TIMEOUT = 1000; +private static final byte[] DATA_TO_CLIENT = "hello client".getBytes(); +private static final byte[] DATA_FROM_CLIENT = "hello server".getBytes(); private X509Util x509Util; private int port; -private volatile boolean handshakeCompleted; +private InetSocketAddress localServerAddress; +private final Object handshakeCompletedLock = new Object(); +// access only inside synchronized(handshakeCompletedLock) { ... } blocks +private boolean handshakeCompleted = false; + +public UnifiedServerSocketTest( +final X509KeyType caKeyType, +final X509KeyType certKeyType, +final Boolean hostnameVerification, +final Integer paramIndex) { +super(paramIndex, () -> { +try { +return X509TestContext.newBuilder() +.setTempDir(tempDir) +.setKeyStoreKeyType(certKeyType) +.setTrustStoreKeyType(caKeyType) +.setHostnameVerification(hostnameVerification) +.build(); +} catch (Exception e) { +throw new RuntimeException(e); +} +}); +} @Before public void setUp() throws Exception { -handshakeCompleted = false; - port = PortAssignment.unique(); +localServerAddress = new InetSocketAddress("localhost", port); --- End diff -- Done ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/679#discussion_r234052921 --- Diff: zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/UnifiedServerSocketTest.java --- @@ -17,156 +17,644 @@ */ package org.apache.zookeeper.server.quorum; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLSocket; + import org.apache.zookeeper.PortAssignment; import org.apache.zookeeper.client.ZKClientConfig; +import org.apache.zookeeper.common.BaseX509ParameterizedTestCase; import org.apache.zookeeper.common.ClientX509Util; -import org.apache.zookeeper.common.Time; +import org.apache.zookeeper.common.KeyStoreFileType; +import org.apache.zookeeper.common.X509Exception; +import org.apache.zookeeper.common.X509KeyType; +import org.apache.zookeeper.common.X509TestContext; import org.apache.zookeeper.common.X509Util; import org.apache.zookeeper.server.ServerCnxnFactory; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; -import javax.net.ssl.HandshakeCompletedEvent; -import javax.net.ssl.HandshakeCompletedListener; -import javax.net.ssl.SSLSocket; -import java.io.IOException; -import java.net.ConnectException; -import java.net.InetSocketAddress; -import java.net.Socket; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; +@RunWith(Parameterized.class) +public class UnifiedServerSocketTest extends BaseX509ParameterizedTestCase { -public class UnifiedServerSocketTest { +@Parameterized.Parameters +public static Collection params() { +ArrayList result = new ArrayList<>(); +int paramIndex = 0; +for (X509KeyType caKeyType : X509KeyType.values()) { +for (X509KeyType certKeyType : X509KeyType.values()) { +for (Boolean hostnameVerification : new Boolean[] { true, false }) { +result.add(new Object[]{ +caKeyType, +certKeyType, +hostnameVerification, +paramIndex++ +}); +} +} +} +return result; +} private static final int MAX_RETRIES = 5; private static final int TIMEOUT = 1000; +private static final byte[] DATA_TO_CLIENT = "hello client".getBytes(); +private static final byte[] DATA_FROM_CLIENT = "hello server".getBytes(); private X509Util x509Util; private int port; -private volatile boolean handshakeCompleted; +private InetSocketAddress localServerAddress; +private final Object handshakeCompletedLock = new Object(); +// access only inside synchronized(handshakeCompletedLock) { ... } blocks +private boolean handshakeCompleted = false; + +public UnifiedServerSocketTest( +final X509KeyType caKeyType, +final X509KeyType certKeyType, +final Boolean hostnameVerification, +final Integer paramIndex) { +super(paramIndex, () -> { +try { +return X509TestContext.newBuilder() +.setTempDir(tempDir) +.setKeyStoreKeyType(certKeyType) +.setTrustStoreKeyType(caKeyType) +.setHostnameVerification(hostnameVerification) +.build(); +} catch (Exception e) { +throw new RuntimeException(e); +} +}); +} @Before public void setUp() throws Exception { -handshakeCompleted = false; - port = PortAssignment.unique(); +localServerAddress = new InetSocketAddress("localhost", port); -String testDataPath = System.getProperty("test.data.dir", "build/test/data"); System.setProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY, "org.apache.zookeeper.server.NettyServerCnxnFactory"); System.setProperty(ZKClientConfig.ZOOKE
[GitHub] zookeeper issue #669: ZOOKEEPER-3152: Port ZK netty stack to netty4
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/669 @anmolnar does anything else need to be done with this PR before it can be merged? ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/679#discussion_r233668370 --- Diff: zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/UnifiedServerSocketTest.java --- @@ -17,156 +17,644 @@ */ package org.apache.zookeeper.server.quorum; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLSocket; + import org.apache.zookeeper.PortAssignment; import org.apache.zookeeper.client.ZKClientConfig; +import org.apache.zookeeper.common.BaseX509ParameterizedTestCase; import org.apache.zookeeper.common.ClientX509Util; -import org.apache.zookeeper.common.Time; +import org.apache.zookeeper.common.KeyStoreFileType; +import org.apache.zookeeper.common.X509Exception; +import org.apache.zookeeper.common.X509KeyType; +import org.apache.zookeeper.common.X509TestContext; import org.apache.zookeeper.common.X509Util; import org.apache.zookeeper.server.ServerCnxnFactory; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; -import javax.net.ssl.HandshakeCompletedEvent; -import javax.net.ssl.HandshakeCompletedListener; -import javax.net.ssl.SSLSocket; -import java.io.IOException; -import java.net.ConnectException; -import java.net.InetSocketAddress; -import java.net.Socket; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; +@RunWith(Parameterized.class) +public class UnifiedServerSocketTest extends BaseX509ParameterizedTestCase { -public class UnifiedServerSocketTest { +@Parameterized.Parameters +public static Collection params() { +ArrayList result = new ArrayList<>(); +int paramIndex = 0; +for (X509KeyType caKeyType : X509KeyType.values()) { +for (X509KeyType certKeyType : X509KeyType.values()) { +for (Boolean hostnameVerification : new Boolean[] { true, false }) { +result.add(new Object[]{ +caKeyType, +certKeyType, +hostnameVerification, +paramIndex++ +}); +} +} +} +return result; +} private static final int MAX_RETRIES = 5; private static final int TIMEOUT = 1000; +private static final byte[] DATA_TO_CLIENT = "hello client".getBytes(); +private static final byte[] DATA_FROM_CLIENT = "hello server".getBytes(); private X509Util x509Util; private int port; -private volatile boolean handshakeCompleted; +private InetSocketAddress localServerAddress; +private final Object handshakeCompletedLock = new Object(); +// access only inside synchronized(handshakeCompletedLock) { ... } blocks +private boolean handshakeCompleted = false; + +public UnifiedServerSocketTest( +final X509KeyType caKeyType, +final X509KeyType certKeyType, +final Boolean hostnameVerification, +final Integer paramIndex) { +super(paramIndex, () -> { +try { +return X509TestContext.newBuilder() +.setTempDir(tempDir) +.setKeyStoreKeyType(certKeyType) +.setTrustStoreKeyType(caKeyType) +.setHostnameVerification(hostnameVerification) +.build(); +} catch (Exception e) { +throw new RuntimeException(e); +} +}); +} @Before public void setUp() throws Exception { -handshakeCompleted = false; - port = PortAssignment.unique(); +localServerAddress = new InetSocketAddress("localhost", port); -String testDataPath = System.getProperty("test.data.dir", "build/test/data"); System.setProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY, "org.apache.zookeeper.server.NettyServerCnxnFactory"); System.setProperty(ZKClientConfig.ZOOKE
[GitHub] zookeeper pull request #669: ZOOKEEPER-3152: Port ZK netty stack to netty4
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/669#discussion_r233663529 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/server/NettyServerCnxnFactory.java --- @@ -116,170 +116,104 @@ public void channelConnected(ChannelHandlerContext ctx, NettyServerCnxn cnxn = new NettyServerCnxn(channel, zkServer, NettyServerCnxnFactory.this); -ctx.setAttachment(cnxn); +ctx.channel().attr(CONNECTION_ATTRIBUTE).set(cnxn); if (secure) { -SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class); -ChannelFuture handshakeFuture = sslHandler.handshake(); +SslHandler sslHandler = ctx.pipeline().get(SslHandler.class); +Future handshakeFuture = sslHandler.handshakeFuture(); handshakeFuture.addListener(new CertificateVerifier(sslHandler, cnxn)); } else { -allChannels.add(ctx.getChannel()); +allChannels.add(ctx.channel()); addCnxn(cnxn); } } @Override -public void channelDisconnected(ChannelHandlerContext ctx, -ChannelStateEvent e) throws Exception -{ +public void channelInactive(ChannelHandlerContext ctx) throws Exception { if (LOG.isTraceEnabled()) { -LOG.trace("Channel disconnected " + e); +LOG.trace("Channel inactive {}", ctx.channel()); } -NettyServerCnxn cnxn = (NettyServerCnxn) ctx.getAttachment(); +allChannels.remove(ctx.channel()); +NettyServerCnxn cnxn = ctx.channel().attr(CONNECTION_ATTRIBUTE).getAndSet(null); if (cnxn != null) { if (LOG.isTraceEnabled()) { -LOG.trace("Channel disconnect caused close " + e); +LOG.trace("Channel inactive caused close {}", cnxn); } cnxn.close(); } } @Override -public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) -throws Exception -{ -LOG.warn("Exception caught " + e, e.getCause()); -NettyServerCnxn cnxn = (NettyServerCnxn) ctx.getAttachment(); +public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { +LOG.warn("Exception caught", cause); +NettyServerCnxn cnxn = ctx.channel().attr(CONNECTION_ATTRIBUTE).getAndSet(null); if (cnxn != null) { if (LOG.isDebugEnabled()) { -LOG.debug("Closing " + cnxn); +LOG.debug("Closing {}", cnxn); } cnxn.close(); } } @Override -public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) -throws Exception -{ -if (LOG.isTraceEnabled()) { -LOG.trace("message received called " + e.getMessage()); -} +public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { try { -if (LOG.isDebugEnabled()) { -LOG.debug("New message " + e.toString() -+ " from " + ctx.getChannel()); -} -NettyServerCnxn cnxn = (NettyServerCnxn)ctx.getAttachment(); -synchronized(cnxn) { -processMessage(e, cnxn); +if (evt == NettyServerCnxn.AutoReadEvent.ENABLE) { +LOG.debug("Received AutoReadEvent.ENABLE"); +NettyServerCnxn cnxn = ctx.channel().attr(CONNECTION_ATTRIBUTE).get(); +// TODO(ilyam): Not sure if cnxn can be null here. It becomes null if channelInactive() --- End diff -- Ah, right. I think I misunderstood. So the code is good as-is, yes? ---
[GitHub] zookeeper pull request #669: ZOOKEEPER-3152: Port ZK netty stack to netty4
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/669#discussion_r233661987 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/server/NettyServerCnxnFactory.java --- @@ -116,170 +116,104 @@ public void channelConnected(ChannelHandlerContext ctx, NettyServerCnxn cnxn = new NettyServerCnxn(channel, zkServer, NettyServerCnxnFactory.this); -ctx.setAttachment(cnxn); +ctx.channel().attr(CONNECTION_ATTRIBUTE).set(cnxn); if (secure) { -SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class); -ChannelFuture handshakeFuture = sslHandler.handshake(); +SslHandler sslHandler = ctx.pipeline().get(SslHandler.class); +Future handshakeFuture = sslHandler.handshakeFuture(); handshakeFuture.addListener(new CertificateVerifier(sslHandler, cnxn)); } else { -allChannels.add(ctx.getChannel()); +allChannels.add(ctx.channel()); addCnxn(cnxn); } } @Override -public void channelDisconnected(ChannelHandlerContext ctx, -ChannelStateEvent e) throws Exception -{ +public void channelInactive(ChannelHandlerContext ctx) throws Exception { if (LOG.isTraceEnabled()) { -LOG.trace("Channel disconnected " + e); +LOG.trace("Channel inactive {}", ctx.channel()); } -NettyServerCnxn cnxn = (NettyServerCnxn) ctx.getAttachment(); +allChannels.remove(ctx.channel()); +NettyServerCnxn cnxn = ctx.channel().attr(CONNECTION_ATTRIBUTE).getAndSet(null); if (cnxn != null) { if (LOG.isTraceEnabled()) { -LOG.trace("Channel disconnect caused close " + e); +LOG.trace("Channel inactive caused close {}", cnxn); } cnxn.close(); } } @Override -public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) -throws Exception -{ -LOG.warn("Exception caught " + e, e.getCause()); -NettyServerCnxn cnxn = (NettyServerCnxn) ctx.getAttachment(); +public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { +LOG.warn("Exception caught", cause); +NettyServerCnxn cnxn = ctx.channel().attr(CONNECTION_ATTRIBUTE).getAndSet(null); if (cnxn != null) { if (LOG.isDebugEnabled()) { -LOG.debug("Closing " + cnxn); +LOG.debug("Closing {}", cnxn); } cnxn.close(); } } @Override -public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) -throws Exception -{ -if (LOG.isTraceEnabled()) { -LOG.trace("message received called " + e.getMessage()); -} +public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { try { -if (LOG.isDebugEnabled()) { -LOG.debug("New message " + e.toString() -+ " from " + ctx.getChannel()); -} -NettyServerCnxn cnxn = (NettyServerCnxn)ctx.getAttachment(); -synchronized(cnxn) { -processMessage(e, cnxn); +if (evt == NettyServerCnxn.AutoReadEvent.ENABLE) { +LOG.debug("Received AutoReadEvent.ENABLE"); +NettyServerCnxn cnxn = ctx.channel().attr(CONNECTION_ATTRIBUTE).get(); +// TODO(ilyam): Not sure if cnxn can be null here. It becomes null if channelInactive() --- End diff -- It will not be called twice, since removing the connection attribute means the second time we will get null and there is a null check in both places. ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/679#discussion_r233661570 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/PrependableSocket.java --- @@ -18,32 +18,47 @@ package org.apache.zookeeper.server.quorum; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.SequenceInputStream; +import java.io.PushbackInputStream; import java.net.Socket; import java.net.SocketImpl; public class PrependableSocket extends Socket { - private SequenceInputStream sequenceInputStream; + private PushbackInputStream pushbackInputStream; --- End diff -- Yes, SequenceInputStream likely still works in practice, but exposes the discontinuity between the underlying streams to the caller. Using PushbackInputStream hides it and I think is preferable. ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/679#discussion_r233657773 --- Diff: zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/UnifiedServerSocketTest.java --- @@ -17,156 +17,644 @@ */ package org.apache.zookeeper.server.quorum; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLSocket; + import org.apache.zookeeper.PortAssignment; import org.apache.zookeeper.client.ZKClientConfig; +import org.apache.zookeeper.common.BaseX509ParameterizedTestCase; import org.apache.zookeeper.common.ClientX509Util; -import org.apache.zookeeper.common.Time; +import org.apache.zookeeper.common.KeyStoreFileType; +import org.apache.zookeeper.common.X509Exception; +import org.apache.zookeeper.common.X509KeyType; +import org.apache.zookeeper.common.X509TestContext; import org.apache.zookeeper.common.X509Util; import org.apache.zookeeper.server.ServerCnxnFactory; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; -import javax.net.ssl.HandshakeCompletedEvent; -import javax.net.ssl.HandshakeCompletedListener; -import javax.net.ssl.SSLSocket; -import java.io.IOException; -import java.net.ConnectException; -import java.net.InetSocketAddress; -import java.net.Socket; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; +@RunWith(Parameterized.class) +public class UnifiedServerSocketTest extends BaseX509ParameterizedTestCase { -public class UnifiedServerSocketTest { +@Parameterized.Parameters +public static Collection params() { +ArrayList result = new ArrayList<>(); +int paramIndex = 0; +for (X509KeyType caKeyType : X509KeyType.values()) { +for (X509KeyType certKeyType : X509KeyType.values()) { +for (Boolean hostnameVerification : new Boolean[] { true, false }) { +result.add(new Object[]{ +caKeyType, +certKeyType, +hostnameVerification, +paramIndex++ +}); +} +} +} +return result; +} private static final int MAX_RETRIES = 5; private static final int TIMEOUT = 1000; +private static final byte[] DATA_TO_CLIENT = "hello client".getBytes(); +private static final byte[] DATA_FROM_CLIENT = "hello server".getBytes(); private X509Util x509Util; private int port; -private volatile boolean handshakeCompleted; +private InetSocketAddress localServerAddress; +private final Object handshakeCompletedLock = new Object(); +// access only inside synchronized(handshakeCompletedLock) { ... } blocks +private boolean handshakeCompleted = false; + +public UnifiedServerSocketTest( +final X509KeyType caKeyType, +final X509KeyType certKeyType, +final Boolean hostnameVerification, +final Integer paramIndex) { +super(paramIndex, () -> { +try { +return X509TestContext.newBuilder() +.setTempDir(tempDir) +.setKeyStoreKeyType(certKeyType) +.setTrustStoreKeyType(caKeyType) +.setHostnameVerification(hostnameVerification) +.build(); +} catch (Exception e) { +throw new RuntimeException(e); +} +}); +} @Before public void setUp() throws Exception { -handshakeCompleted = false; - port = PortAssignment.unique(); +localServerAddress = new InetSocketAddress("localhost", port); -String testDataPath = System.getProperty("test.data.dir", "build/test/data"); System.setProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY, "org.apache.zookeeper.server.NettyServerCnxnFactory"); System.setProperty(ZKClientConfig.ZOOKE
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/679#discussion_r233657163 --- Diff: zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/UnifiedServerSocketTest.java --- @@ -17,156 +17,644 @@ */ package org.apache.zookeeper.server.quorum; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLSocket; + import org.apache.zookeeper.PortAssignment; import org.apache.zookeeper.client.ZKClientConfig; +import org.apache.zookeeper.common.BaseX509ParameterizedTestCase; import org.apache.zookeeper.common.ClientX509Util; -import org.apache.zookeeper.common.Time; +import org.apache.zookeeper.common.KeyStoreFileType; +import org.apache.zookeeper.common.X509Exception; +import org.apache.zookeeper.common.X509KeyType; +import org.apache.zookeeper.common.X509TestContext; import org.apache.zookeeper.common.X509Util; import org.apache.zookeeper.server.ServerCnxnFactory; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; -import javax.net.ssl.HandshakeCompletedEvent; -import javax.net.ssl.HandshakeCompletedListener; -import javax.net.ssl.SSLSocket; -import java.io.IOException; -import java.net.ConnectException; -import java.net.InetSocketAddress; -import java.net.Socket; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; +@RunWith(Parameterized.class) +public class UnifiedServerSocketTest extends BaseX509ParameterizedTestCase { -public class UnifiedServerSocketTest { +@Parameterized.Parameters +public static Collection params() { +ArrayList result = new ArrayList<>(); +int paramIndex = 0; +for (X509KeyType caKeyType : X509KeyType.values()) { +for (X509KeyType certKeyType : X509KeyType.values()) { +for (Boolean hostnameVerification : new Boolean[] { true, false }) { +result.add(new Object[]{ +caKeyType, +certKeyType, +hostnameVerification, +paramIndex++ +}); +} +} +} +return result; +} private static final int MAX_RETRIES = 5; private static final int TIMEOUT = 1000; +private static final byte[] DATA_TO_CLIENT = "hello client".getBytes(); +private static final byte[] DATA_FROM_CLIENT = "hello server".getBytes(); private X509Util x509Util; private int port; -private volatile boolean handshakeCompleted; +private InetSocketAddress localServerAddress; +private final Object handshakeCompletedLock = new Object(); +// access only inside synchronized(handshakeCompletedLock) { ... } blocks +private boolean handshakeCompleted = false; + +public UnifiedServerSocketTest( +final X509KeyType caKeyType, +final X509KeyType certKeyType, +final Boolean hostnameVerification, +final Integer paramIndex) { +super(paramIndex, () -> { +try { +return X509TestContext.newBuilder() +.setTempDir(tempDir) +.setKeyStoreKeyType(certKeyType) +.setTrustStoreKeyType(caKeyType) +.setHostnameVerification(hostnameVerification) +.build(); +} catch (Exception e) { +throw new RuntimeException(e); +} +}); +} @Before public void setUp() throws Exception { -handshakeCompleted = false; - port = PortAssignment.unique(); +localServerAddress = new InetSocketAddress("localhost", port); -String testDataPath = System.getProperty("test.data.dir", "build/test/data"); System.setProperty(ServerCnxnFactory.ZOOKEEPER_SERVER_CNXN_FACTORY, "org.apache.zookeeper.server.NettyServerCnxnFactory"); System.setProperty(ZKClientConfig.ZOOKE
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/679#discussion_r233656740 --- Diff: zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/UnifiedServerSocketTest.java --- @@ -17,156 +17,644 @@ */ package org.apache.zookeeper.server.quorum; +import java.io.BufferedInputStream; +import java.io.IOException; +import java.net.ConnectException; +import java.net.InetSocketAddress; +import java.net.Socket; +import java.net.SocketException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Random; + +import javax.net.ssl.HandshakeCompletedEvent; +import javax.net.ssl.HandshakeCompletedListener; +import javax.net.ssl.SSLSocket; + import org.apache.zookeeper.PortAssignment; import org.apache.zookeeper.client.ZKClientConfig; +import org.apache.zookeeper.common.BaseX509ParameterizedTestCase; import org.apache.zookeeper.common.ClientX509Util; -import org.apache.zookeeper.common.Time; +import org.apache.zookeeper.common.KeyStoreFileType; +import org.apache.zookeeper.common.X509Exception; +import org.apache.zookeeper.common.X509KeyType; +import org.apache.zookeeper.common.X509TestContext; import org.apache.zookeeper.common.X509Util; import org.apache.zookeeper.server.ServerCnxnFactory; import org.junit.Assert; import org.junit.Before; import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; -import javax.net.ssl.HandshakeCompletedEvent; -import javax.net.ssl.HandshakeCompletedListener; -import javax.net.ssl.SSLSocket; -import java.io.IOException; -import java.net.ConnectException; -import java.net.InetSocketAddress; -import java.net.Socket; - -import static org.hamcrest.CoreMatchers.equalTo; -import static org.junit.Assert.assertThat; +@RunWith(Parameterized.class) +public class UnifiedServerSocketTest extends BaseX509ParameterizedTestCase { -public class UnifiedServerSocketTest { +@Parameterized.Parameters +public static Collection params() { +ArrayList result = new ArrayList<>(); +int paramIndex = 0; +for (X509KeyType caKeyType : X509KeyType.values()) { +for (X509KeyType certKeyType : X509KeyType.values()) { +for (Boolean hostnameVerification : new Boolean[] { true, false }) { +result.add(new Object[]{ +caKeyType, +certKeyType, +hostnameVerification, +paramIndex++ +}); +} +} +} +return result; +} private static final int MAX_RETRIES = 5; private static final int TIMEOUT = 1000; +private static final byte[] DATA_TO_CLIENT = "hello client".getBytes(); +private static final byte[] DATA_FROM_CLIENT = "hello server".getBytes(); private X509Util x509Util; private int port; -private volatile boolean handshakeCompleted; +private InetSocketAddress localServerAddress; +private final Object handshakeCompletedLock = new Object(); +// access only inside synchronized(handshakeCompletedLock) { ... } blocks +private boolean handshakeCompleted = false; + +public UnifiedServerSocketTest( +final X509KeyType caKeyType, +final X509KeyType certKeyType, +final Boolean hostnameVerification, +final Integer paramIndex) { +super(paramIndex, () -> { +try { +return X509TestContext.newBuilder() +.setTempDir(tempDir) +.setKeyStoreKeyType(certKeyType) +.setTrustStoreKeyType(caKeyType) +.setHostnameVerification(hostnameVerification) +.build(); +} catch (Exception e) { +throw new RuntimeException(e); +} +}); +} @Before public void setUp() throws Exception { -handshakeCompleted = false; - port = PortAssignment.unique(); +localServerAddress = new InetSocketAddress("localhost", port); --- End diff -- Sure, I could do that if you prefer. ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/679#discussion_r233656201 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/common/X509Util.java --- @@ -350,14 +389,22 @@ public static X509TrustManager createTrustManager( public SSLSocket createSSLSocket() throws X509Exception, IOException { SSLSocket sslSocket = (SSLSocket) getDefaultSSLContext().getSocketFactory().createSocket(); configureSSLSocket(sslSocket); - +sslSocket.setUseClientMode(true); return sslSocket; } -public SSLSocket createSSLSocket(Socket socket) throws X509Exception, IOException { -SSLSocket sslSocket = (SSLSocket) getDefaultSSLContext().getSocketFactory().createSocket(socket, null, socket.getPort(), true); +public SSLSocket createSSLSocket(Socket socket, byte[] pushbackBytes) throws X509Exception, IOException { +SSLSocket sslSocket; +if (pushbackBytes != null && pushbackBytes.length > 0) { +sslSocket = (SSLSocket) getDefaultSSLContext().getSocketFactory().createSocket( +socket, new ByteArrayInputStream(pushbackBytes), true); +} else { +sslSocket = (SSLSocket) getDefaultSSLContext().getSocketFactory().createSocket( +socket, null, socket.getPort(), true); +} configureSSLSocket(sslSocket); - +sslSocket.setUseClientMode(false); --- End diff -- Yes and yes. In #681 I make the client auth setting configurable. ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/679#discussion_r233656579 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/PrependableSocket.java --- @@ -18,32 +18,47 @@ package org.apache.zookeeper.server.quorum; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.io.InputStream; -import java.io.SequenceInputStream; +import java.io.PushbackInputStream; import java.net.Socket; import java.net.SocketImpl; public class PrependableSocket extends Socket { - private SequenceInputStream sequenceInputStream; + private PushbackInputStream pushbackInputStream; --- End diff -- I don't know why it worked like that, but that is what I observed in tests. It looks like SequenceInputStream does not join returned data across boundaries of the underlying streams when the first stream gets to EOF. I don't think this is desired behavior since it would cause the stream to return 5 bytes when more than 5 bytes are actually available. ---
[GitHub] zookeeper pull request #669: ZOOKEEPER-3152: Port ZK netty stack to netty4
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/669#discussion_r233651445 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/server/NettyServerCnxnFactory.java --- @@ -316,16 +251,17 @@ public void operationComplete(ChannelFuture future) if (KeeperException.Code.OK != authProvider.handleAuthentication(cnxn, null)) { LOG.error("Authentication failed for session 0x{}", -Long.toHexString(cnxn.sessionId)); +Long.toHexString(cnxn.getSessionId())); cnxn.close(); return; } -allChannels.add(future.getChannel()); +final Channel futureChannel = future.getNow(); --- End diff -- I think they are equivalent here since we know the future is completed (we are inside a `if (future.isSuccess())` block). I can change it to `get()` if you prefer. ---
[GitHub] zookeeper pull request #669: ZOOKEEPER-3152: Port ZK netty stack to netty4
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/669#discussion_r233651730 --- Diff: zookeeper-server/src/test/java/org/apache/zookeeper/test/TestByteBufAllocator.java --- @@ -0,0 +1,152 @@ +/* + * 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 java.util.ArrayList; +import java.util.List; +import java.util.Objects; +import java.util.concurrent.atomic.AtomicReference; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.CompositeByteBuf; +import io.netty.buffer.PooledByteBufAllocator; +import io.netty.util.ResourceLeakDetector; + +/** + * This is a custom ByteBufAllocator that tracks outstanding allocations and + * crashes the program if any of them are leaked. + * + * Never use this class in production, it will cause your server to run out + * of memory! This is because it holds strong references to all allocated + * buffers and doesn't release them until checkForLeaks() is called at the + * end of a unit test. + * + * Note: the original code was copied from https://github.com/airlift/drift, + * with the permission and encouragement of airlift's author (dain). Airlift + * uses the same apache 2.0 license as Zookeeper so this should be ok. + * + * However, the code was modified to take advantage of Netty's built-in + * leak tracking and make a best effort to print details about buffer leaks. + * + */ +public class TestByteBufAllocator extends PooledByteBufAllocator { +private static AtomicReference INSTANCE = +new AtomicReference<>(null); + +/** + * Get the singleton testing allocator. + * @return the singleton allocator, creating it if one does not exist. + */ +public static TestByteBufAllocator getInstance() { +TestByteBufAllocator result = INSTANCE.get(); +if (result == null) { +ResourceLeakDetector.Level oldLevel = ResourceLeakDetector.getLevel(); + ResourceLeakDetector.setLevel(ResourceLeakDetector.Level.PARANOID); +INSTANCE.compareAndSet(null, new TestByteBufAllocator(oldLevel)); +result = INSTANCE.get(); +} +return result; +} + +/** + * Destroys the singleton testing allocator and throws an error if any of the + * buffers allocated by it have been leaked. Attempts to print leak details to + * standard error before throwing, by using netty's built-in leak tracking. + * Note that this might not always work, since it only triggers when a buffer + * is garbage-collected and calling System.gc() does not guarantee that a buffer + * will actually be GC'ed. + * + * This should be called at the end of a unit test's tearDown() method. + */ +public static void checkForLeaks() { +TestByteBufAllocator result = INSTANCE.getAndSet(null); +if (result != null) { +result.checkInstanceForLeaks(); +} +} + +private final List trackedBuffers = new ArrayList<>(); +private final ResourceLeakDetector.Level oldLevel; + +private TestByteBufAllocator(ResourceLeakDetector.Level oldLevel) +{ +super(false); +this.oldLevel = oldLevel; +} + +@Override +protected ByteBuf newHeapBuffer(int initialCapacity, int maxCapacity) +{ +return track(super.newHeapBuffer(initialCapacity, maxCapacity)); +} + +@Override +protected ByteBuf newDirectBuffer(int initialCapacity, int maxCapacity) +{ +return track(super.newDirectBuffer(initialCapacity, maxCapacity)); +} + +@Override +public CompositeByteBuf compositeHeapBuffer(int maxNumComponents) +{ +return track(super.comp
[GitHub] zookeeper pull request #669: ZOOKEEPER-3152: Port ZK netty stack to netty4
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/669#discussion_r233650367 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/server/NettyServerCnxnFactory.java --- @@ -116,170 +116,104 @@ public void channelConnected(ChannelHandlerContext ctx, NettyServerCnxn cnxn = new NettyServerCnxn(channel, zkServer, NettyServerCnxnFactory.this); -ctx.setAttachment(cnxn); +ctx.channel().attr(CONNECTION_ATTRIBUTE).set(cnxn); if (secure) { -SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class); -ChannelFuture handshakeFuture = sslHandler.handshake(); +SslHandler sslHandler = ctx.pipeline().get(SslHandler.class); +Future handshakeFuture = sslHandler.handshakeFuture(); handshakeFuture.addListener(new CertificateVerifier(sslHandler, cnxn)); } else { -allChannels.add(ctx.getChannel()); +allChannels.add(ctx.channel()); addCnxn(cnxn); } } @Override -public void channelDisconnected(ChannelHandlerContext ctx, -ChannelStateEvent e) throws Exception -{ +public void channelInactive(ChannelHandlerContext ctx) throws Exception { if (LOG.isTraceEnabled()) { -LOG.trace("Channel disconnected " + e); +LOG.trace("Channel inactive {}", ctx.channel()); } -NettyServerCnxn cnxn = (NettyServerCnxn) ctx.getAttachment(); +allChannels.remove(ctx.channel()); +NettyServerCnxn cnxn = ctx.channel().attr(CONNECTION_ATTRIBUTE).getAndSet(null); if (cnxn != null) { if (LOG.isTraceEnabled()) { -LOG.trace("Channel disconnect caused close " + e); +LOG.trace("Channel inactive caused close {}", cnxn); } cnxn.close(); } } @Override -public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) -throws Exception -{ -LOG.warn("Exception caught " + e, e.getCause()); -NettyServerCnxn cnxn = (NettyServerCnxn) ctx.getAttachment(); +public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { +LOG.warn("Exception caught", cause); +NettyServerCnxn cnxn = ctx.channel().attr(CONNECTION_ATTRIBUTE).getAndSet(null); if (cnxn != null) { if (LOG.isDebugEnabled()) { -LOG.debug("Closing " + cnxn); +LOG.debug("Closing {}", cnxn); } cnxn.close(); } } @Override -public void messageReceived(ChannelHandlerContext ctx, MessageEvent e) -throws Exception -{ -if (LOG.isTraceEnabled()) { -LOG.trace("message received called " + e.getMessage()); -} +public void userEventTriggered(ChannelHandlerContext ctx, Object evt) throws Exception { try { -if (LOG.isDebugEnabled()) { -LOG.debug("New message " + e.toString() -+ " from " + ctx.getChannel()); -} -NettyServerCnxn cnxn = (NettyServerCnxn)ctx.getAttachment(); -synchronized(cnxn) { -processMessage(e, cnxn); +if (evt == NettyServerCnxn.AutoReadEvent.ENABLE) { +LOG.debug("Received AutoReadEvent.ENABLE"); +NettyServerCnxn cnxn = ctx.channel().attr(CONNECTION_ATTRIBUTE).get(); +// TODO(ilyam): Not sure if cnxn can be null here. It becomes null if channelInactive() --- End diff -- I do remove it in both places, by calling `ctx.channel().attr(CONNECTION_ATTRIBUTE).getAndSet(null)`. The getAndSet(null) will atomically return the old value of the attribute and set the new value to null. Now that I think about it, I'm not sure if we need to remove the attribute in `exceptionCaught()` ... we can probably leave it and let `channelInactive()` take care of removing the attribute. Let me know if you want me to make this change, I think it probably doesn't matter too much either way. ---
[GitHub] zookeeper pull request #669: ZOOKEEPER-3152: Port ZK netty stack to netty4
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/669#discussion_r233652712 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/ClientCnxnSocketNetty.java --- @@ -103,71 +105,102 @@ boolean isConnected() { // Assuming that isConnected() is only used to initiate connection, // not used by some other connection status judgement. -return channel != null; +connectLock.lock(); +try { +return channel != null || connectFuture != null; --- End diff -- As the comment above says, the `isConnected()` method is only used in the main loop inside `ClientCnxn$SendThread.run()` to see if a new connection should be initiated. So, this method should return false if a connection attempt is already in progress. This is the case when `connectFuture` is not null. Arguably the method should be called `isConnectedOrConnecting()` but I didn't want to go around refactoring APIs in this diff - can do it if you like. ---
[GitHub] zookeeper pull request #669: ZOOKEEPER-3152: Port ZK netty stack to netty4
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/669#discussion_r233653584 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/ClientCnxnSocketNetty.java --- @@ -103,71 +105,102 @@ boolean isConnected() { // Assuming that isConnected() is only used to initiate connection, // not used by some other connection status judgement. -return channel != null; +connectLock.lock(); +try { +return channel != null || connectFuture != null; +} finally { +connectLock.unlock(); +} +} + +private Bootstrap configureBootstrapAllocator(Bootstrap bootstrap) { +ByteBufAllocator testAllocator = TEST_ALLOCATOR.get(); +if (testAllocator != null) { +return bootstrap.option(ChannelOption.ALLOCATOR, testAllocator); +} else { +return bootstrap; +} } @Override void connect(InetSocketAddress addr) throws IOException { firstConnect = new CountDownLatch(1); -ClientBootstrap bootstrap = new ClientBootstrap(channelFactory); - -bootstrap.setPipelineFactory(new ZKClientPipelineFactory(addr.getHostString(), addr.getPort())); -bootstrap.setOption("soLinger", -1); -bootstrap.setOption("tcpNoDelay", true); - -connectFuture = bootstrap.connect(addr); -connectFuture.addListener(new ChannelFutureListener() { -@Override -public void operationComplete(ChannelFuture channelFuture) throws Exception { -// this lock guarantees that channel won't be assgined after cleanup(). -connectLock.lock(); -try { -if (!channelFuture.isSuccess() || connectFuture == null) { -LOG.info("future isn't success, cause: {}", channelFuture.getCause()); -return; -} -// setup channel, variables, connection, etc. -channel = channelFuture.getChannel(); - -disconnected.set(false); -initialized = false; -lenBuffer.clear(); -incomingBuffer = lenBuffer; - -sendThread.primeConnection(); -updateNow(); -updateLastSendAndHeard(); - -if (sendThread.tunnelAuthInProgress()) { -waitSasl.drainPermits(); -needSasl.set(true); -sendPrimePacket(); -} else { -needSasl.set(false); -} +Bootstrap bootstrap = new Bootstrap() +.group(eventLoopGroup) +.channel(NettyUtils.nioOrEpollSocketChannel()) +.option(ChannelOption.SO_LINGER, -1) +.option(ChannelOption.TCP_NODELAY, true) +.handler(new ZKClientPipelineFactory(addr.getHostString(), addr.getPort())); +bootstrap = configureBootstrapAllocator(bootstrap); +bootstrap.validate(); -// we need to wake up on first connect to avoid timeout. -wakeupCnxn(); -firstConnect.countDown(); -LOG.info("channel is connected: {}", channelFuture.getChannel()); -} finally { -connectLock.unlock(); +connectLock.lock(); +try { +connectFuture = bootstrap.connect(addr); +connectFuture.addListener(new ChannelFutureListener() { +@Override +public void operationComplete(ChannelFuture channelFuture) throws Exception { +// this lock guarantees that channel won't be assigned after cleanup(). +connectLock.lock(); +try { +if (!channelFuture.isSuccess()) { +LOG.info("future isn't success, cause:", channelFuture.cause()); +return; +} else if (connectFuture == null) { --- End diff -- As the comment below says, there could be a race if the connect attempt was cancelled right around the time the listener callback fired. `cleanup()` below will cancel an in-progress connection attempt and clear the `connectFuture` variable. If this happens, `connectFuture` will be null here. ---
[GitHub] zookeeper pull request #669: ZOOKEEPER-3152: Port ZK netty stack to netty4
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/669#discussion_r233649908 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/server/NettyServerCnxnFactory.java --- @@ -116,170 +116,104 @@ public void channelConnected(ChannelHandlerContext ctx, NettyServerCnxn cnxn = new NettyServerCnxn(channel, zkServer, NettyServerCnxnFactory.this); -ctx.setAttachment(cnxn); +ctx.channel().attr(CONNECTION_ATTRIBUTE).set(cnxn); if (secure) { -SslHandler sslHandler = ctx.getPipeline().get(SslHandler.class); -ChannelFuture handshakeFuture = sslHandler.handshake(); +SslHandler sslHandler = ctx.pipeline().get(SslHandler.class); +Future handshakeFuture = sslHandler.handshakeFuture(); handshakeFuture.addListener(new CertificateVerifier(sslHandler, cnxn)); } else { -allChannels.add(ctx.getChannel()); +allChannels.add(ctx.channel()); addCnxn(cnxn); } } @Override -public void channelDisconnected(ChannelHandlerContext ctx, -ChannelStateEvent e) throws Exception -{ +public void channelInactive(ChannelHandlerContext ctx) throws Exception { if (LOG.isTraceEnabled()) { -LOG.trace("Channel disconnected " + e); +LOG.trace("Channel inactive {}", ctx.channel()); } -NettyServerCnxn cnxn = (NettyServerCnxn) ctx.getAttachment(); +allChannels.remove(ctx.channel()); +NettyServerCnxn cnxn = ctx.channel().attr(CONNECTION_ATTRIBUTE).getAndSet(null); if (cnxn != null) { if (LOG.isTraceEnabled()) { -LOG.trace("Channel disconnect caused close " + e); +LOG.trace("Channel inactive caused close {}", cnxn); } cnxn.close(); } } @Override -public void exceptionCaught(ChannelHandlerContext ctx, ExceptionEvent e) -throws Exception -{ -LOG.warn("Exception caught " + e, e.getCause()); -NettyServerCnxn cnxn = (NettyServerCnxn) ctx.getAttachment(); +public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) throws Exception { --- End diff -- We call `cnxn.close()` at the end of `exceptionCaught()`, which will end up closing the channel so `channelInactive()` will get called, so I think it would be redundant to remove from `allChannels` here. ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/680 ZOOKEEPER-3174: Quorum TLS - support reloading trust/key store Allow reloading SSL trust stores and key stores from disk when the files on disk change. Note that this is stacked on top of #678 and #679 and thus includes them. Please only consider the ZOOKEEPER-3174 commit when reviewing. Once the other PRs are merged upstream, I will rebase this so it only contains one commit. ## Added support for reloading key/trust stores when the file on disk changes - new property `sslQuorumReloadCertFiles` which controls the behavior for reloading the key and trust store files for `QuorumX509Util`. Reloading of key and trust store for `ClientX509Util` is not in this PR but could be added easily - this allows a ZK server to keep running on a machine that uses short-lived certs that refresh frequently without having to restart the ZK process. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3174 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/680.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #680 commit 33f7aaab6fe16122b7e1faedbb408d739bbe8a30 Author: Ilya Maykov Date: 2018-10-25T01:22:24Z ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades commit 30adde0fa951d5d99b6b33370eca9736e370a952 Author: Ilya Maykov Date: 2018-10-25T01:54:06Z ZOOKEEPER-3174: Quorum TLS - support reloading trust/key store ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/680 ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/679 ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades Fix numerous problems with UnifiedServerSocket, such as hanging the accept() thread when the client doesn't send any data or crashing if less than 5 bytes are read from the socket in the initial read. Re-enable the "portUnification" config option. ## Fixed networking issues/bugs in UnifiedServerSocket - don't crash the `accept()` thread if the client closes the connection without sending any data - don't corrupt the connection if the client sends fewer than 5 bytes for the initial read - delay the detection of TLS vs. plaintext mode until a socket stream is read from or written to. This prevents the `accept()` thread from getting blocked on a `read()` operation from the newly connected socket. - prepending 5 bytes to `PrependableSocket` and then trying to read >5 bytes would only return the first 5 bytes, even if more bytes were available. This is fixed. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3172 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/679.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #679 commit 33f7aaab6fe16122b7e1faedbb408d739bbe8a30 Author: Ilya Maykov Date: 2018-10-25T01:22:24Z ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/679 ---
[GitHub] zookeeper issue #679: ZOOKEEPER-3172: Quorum TLS - fix port unification to a...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/679 Don't use UnifiedServerSocket for the non-port-unification path in this PR, since cert reloading is not yet available here. ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/680#discussion_r231969309 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/common/FileChangeWatcher.java --- @@ -0,0 +1,191 @@ +/** + * 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.common; + +import com.sun.nio.file.SensitivityWatchEventModifier; +import org.apache.zookeeper.server.ZooKeeperThread; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.file.ClosedWatchServiceException; +import java.nio.file.FileSystem; +import java.nio.file.Path; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.util.function.Consumer; + +/** + * Instances of this class can be used to watch a directory for file changes. When a file is added to, deleted from, + * or is modified in the given directory, the callback provided by the user will be called from a background thread. + * Some things to keep in mind: + * + * The callback should be thread-safe. + * Changes that happen around the time the thread is started may be missed. + * There is a delay between a file changing and the callback firing. + * The watch is not recursive - changes to subdirectories will not trigger a callback. + * + */ +public final class FileChangeWatcher { +private static final Logger LOG = LoggerFactory.getLogger(FileChangeWatcher.class); + +public enum State { +NEW, // object created but start() not called yet +STARTING, // start() called but background thread has not entered main loop +RUNNING, // background thread is running +STOPPING, // stop() called but background thread has not exited main loop +STOPPED // stop() called and background thread has exited, or background thread crashed +} + +private final WatcherThread watcherThread; +private State state; // protected by synchronized(this) + +/** + * Creates a watcher that watches dirPath and invokes callback on changes. + * + * @param dirPath the directory to watch. + * @param callback the callback to invoke with events. event.kind() will return the type of event, + * and event.context() will return the filename relative to dirPath. + * @throws IOException if there is an error creating the WatchService. + */ +public FileChangeWatcher(Path dirPath, Consumer> callback) throws IOException { +FileSystem fs = dirPath.getFileSystem(); +WatchService watchService = fs.newWatchService(); +if (LOG.isDebugEnabled()) { +LOG.debug("Registering with watch service: " + dirPath); +} +dirPath.register( +watchService, +new WatchEvent.Kind[]{ +StandardWatchEventKinds.ENTRY_CREATE, +StandardWatchEventKinds.ENTRY_DELETE, +StandardWatchEventKinds.ENTRY_MODIFY, +StandardWatchEventKinds.OVERFLOW}, +SensitivityWatchEventModifier.HIGH); +state = State.NEW; +this.watcherThread = new WatcherThread(watchService, callback); +this.watcherThread.setDaemon(true); +} + +public synchronized State getState() { +return state; +} + +private synchronized void setState(State newState) { +state = newState; +this.notifyAll(); +} + +/** + * Tells the background thread to start. Does not wait for it to be running. + * Calling this method more than once has no effect. + */ +public synchronized void start() {
[GitHub] zookeeper pull request #681: ZOOKEEPER-3176: Quorum TLS - add SSL config opt...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/681 ZOOKEEPER-3176: Quorum TLS - add SSL config options Add SSL config options for enabled protocols and client auth mode. Improve handling of SSL config options for protocols and cipher suites - previously these came from system properties, now they can come from ZKConfig which means they are easier to isolate in tests, and now we don't need to parse system properties every time we create a secure socket. Note that this is stacked on top of #678, #679, and #680 and thus includes them. Please only consider the ZOOKEEPER-3176 commit when reviewing. Once the other PRs are merged upstream, I will rebase this so it only contains one commit. ## Added more options for ssl settings to X509Util and encapsulate them better - previously, some SSL settings came from a `ZKConfig` and others came from global `System.getProperties()`. This made it hard to isolate certain settings in tests. - now all SSL-related settings come from the `ZKConfig` object used to create the SSL context - new settings added: - `zookeeper.ssl(.quorum).enabledProtocols` - list of enabled protocols. If not set, defaults to a single-entry list with the value of `zookeeper.ssl(.quorum).protocol`. - `zookeeper.ssl(.quorum).clientAuth` - can be "NONE", "WANT", or "NEED". This controls whether the server doesn't want / allows / requires the client to present an X509 certificate. - `zookeeper.ssl(.quorum).handshakeDetectionTimeoutMillis` - timeout for the first read of 5 bytes to detect the transport mode (TLS or plaintext) of a client connection made to a `UnifiedServerSocket` You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3176 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/681.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #681 commit b45b716a59709b933c0652f48d563b08e1091e92 Author: Ilya Maykov Date: 2018-10-25T01:22:24Z ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades commit 28565e3466dd35a339a3d1d71de20298072abb1a Author: Ilya Maykov Date: 2018-10-25T01:54:06Z ZOOKEEPER-3174: Quorum TLS - support reloading trust/key store commit 4bd95d4d0f69fa73342e2c6af57c38e41421e140 Author: Ilya Maykov Date: 2018-10-25T02:12:04Z ZOOKEEPER-3176: Quorum TLS - add SSL config options ---
[GitHub] zookeeper pull request #681: ZOOKEEPER-3176: Quorum TLS - add SSL config opt...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/681 ---
[GitHub] zookeeper pull request #669: ZOOKEEPER-3152: Port ZK netty stack to netty4
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/669 ZOOKEEPER-3152: Port ZK netty stack to netty4 Summary: Ported the client connection netty stack from netty3 to netty4. This includes both the server side (NettyServerCnxn and friends) and the client side (ClientCnxnSocketNetty). Test Plan: Modified `FourLetterWordsTest` and `NettyServerCnxnTest`, plus manual testing on a regional ensemble. FB Reviewers: nixon You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3152 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/669.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #669 commit 94c4516bea9b46f5428ef29ff51490f9647eaac3 Author: Ilya Maykov Date: 2018-08-31T23:26:55Z port ZK netty stack from netty3 to netty4 Summary: Ported the client connection netty stack from netty3 to netty4. This includes both the server side (NettyServerCnxn and friends) and the client side (ClientCnxnSocketNetty). Test Plan: Modified `FourLetterWordsTest` and `NettyServerCnxnTest`, plus manual testing on a regional ensemble. Reviewers: nixon, nwolchko, nedelchev Subscribers: Differential Revision: https://phabricator.intern.facebook.com/D9646262 Tasks: Tags: Blame Revision: ---
[GitHub] zookeeper pull request #669: ZOOKEEPER-3152: Port ZK netty stack to netty4
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/669 ---
[GitHub] zookeeper issue #678: ZOOKEEPER-3173: Quorum TLS - support PEM trust/key sto...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/678 @anmolnar thanks for merging this :) I've rebased #679, #680, and #681 on top of master. Let's get those in soon :) ---
[GitHub] zookeeper issue #679: ZOOKEEPER-3172: Quorum TLS - fix port unification to a...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/679 Rebase on latest master, no longer includes #678 as it has been merged upstream. ---
[GitHub] zookeeper issue #678: ZOOKEEPER-3173: Quorum TLS - support PEM trust/key sto...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/678 @anmolnar the latest attempt does not have test failures, but claims a findbugs failure. >[exec] -1 overall. GitHub Pull Request Build >[exec] >[exec] >[exec] +1 @author. The patch does not contain any @author tags. >[exec] >[exec] +0 tests included. The patch appears to be a documentation patch that doesn't require tests. >[exec] >[exec] +1 javadoc. The javadoc tool did not generate any warning messages. >[exec] >[exec] +1 javac. The applied patch does not increase the total number of javac compiler warnings. >[exec] >[exec] -1 findbugs. The patch appears to cause Findbugs (version 3.0.1) to fail. >[exec] >[exec] +1 release audit. The applied patch does not increase the total number of release audit warnings. >[exec] >[exec] +1 core tests. The patch passed core unit tests. >[exec] >[exec] +1 contrib tests. The patch passed contrib unit tests. Link to full output: https://builds.apache.org/job/PreCommit-ZOOKEEPER-github-pr-build/2599/console ---
[GitHub] zookeeper issue #678: ZOOKEEPER-3173: Quorum TLS - support PEM trust/key sto...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/678 Jenkins claims there is a findbugs failure, but there is no actual output of findbugs failures, and findbugs passes on my machine. ¯\_(ã)_/¯ ---
[GitHub] zookeeper issue #678: ZOOKEEPER-3173: Quorum TLS - support PEM trust/key sto...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/678 I don't understand why this PR started failing Jenkins builds all of a sudden. The next 2 PRs stacked on this one (#678 and #680) also fail, but the last one (#681) passes. ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/679 ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades Fix numerous problems with UnifiedServerSocket, such as hanging the accept() thread when the client doesn't send any data or crashing if less than 5 bytes are read from the socket in the initial read. Re-enable the "portUnification" config option. Note that this is stacked on top of #678 and thus includes it. Please only consider the ZOOKEEPER-3172 commit when reviewing. Once the other PR is merged upstream, I will rebase this so it only contains one commit. ## Fixed networking issues/bugs in UnifiedServerSocket - don't crash the `accept()` thread if the client closes the connection without sending any data - don't corrupt the connection if the client sends fewer than 5 bytes for the initial read - delay the detection of TLS vs. plaintext mode until a socket stream is read from or written to. This prevents the `accept()` thread from getting blocked on a `read()` operation from the newly connected socket. - prepending 5 bytes to `PrependableSocket` and then trying to read >5 bytes would only return the first 5 bytes, even if more bytes were available. This is fixed. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3172 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/679.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #679 commit 2122c8c23a0dbb27f9b2aff55e800e48d253f943 Author: Ilya Maykov Date: 2018-10-25T00:41:48Z ZOOKEEPER-3173: Quorum TLS - support PEM trust/key stores ZOOKEEPER-3175: Quorum TLS - test improvements Add support for loading key and trust stores from PEM files. Also added test utils for testing X509-related code, because it was very difficult to untangle them from the PEM support code. commit 514d48a26aeeca37290ad14ff8f0cdae69b53eb2 Author: Ilya Maykov Date: 2018-10-25T01:22:24Z ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/679 ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/679 ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades Fix numerous problems with UnifiedServerSocket, such as hanging the accept() thread when the client doesn't send any data or crashing if less than 5 bytes are read from the socket in the initial read. Re-enable the "portUnification" config option. Note that this is stacked on top of #678 and thus includes it. Please only consider the ZOOKEEPER-3172 commit when reviewing. Once the other PR is merged upstream, I will rebase this so it only contains one commit. ## Fixed networking issues/bugs in UnifiedServerSocket - don't crash the `accept()` thread if the client closes the connection without sending any data - don't corrupt the connection if the client sends fewer than 5 bytes for the initial read - delay the detection of TLS vs. plaintext mode until a socket stream is read from or written to. This prevents the `accept()` thread from getting blocked on a `read()` operation from the newly connected socket. - prepending 5 bytes to `PrependableSocket` and then trying to read >5 bytes would only return the first 5 bytes, even if more bytes were available. This is fixed. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3172 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/679.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #679 commit 2122c8c23a0dbb27f9b2aff55e800e48d253f943 Author: Ilya Maykov Date: 2018-10-25T00:41:48Z ZOOKEEPER-3173: Quorum TLS - support PEM trust/key stores ZOOKEEPER-3175: Quorum TLS - test improvements Add support for loading key and trust stores from PEM files. Also added test utils for testing X509-related code, because it was very difficult to untangle them from the PEM support code. commit 514d48a26aeeca37290ad14ff8f0cdae69b53eb2 Author: Ilya Maykov Date: 2018-10-25T01:22:24Z ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/679 ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/680 ZOOKEEPER-3174: Quorum TLS - support reloading trust/key store Allow reloading SSL trust stores and key stores from disk when the files on disk change. Note that this is stacked on top of #678 and #679 and thus includes them. Please only consider the ZOOKEEPER-3174 commit when reviewing. Once the other PRs are merged upstream, I will rebase this so it only contains one commit. ## Added support for reloading key/trust stores when the file on disk changes - new property `sslQuorumReloadCertFiles` which controls the behavior for reloading the key and trust store files for `QuorumX509Util`. Reloading of key and trust store for `ClientX509Util` is not in this PR but could be added easily - this allows a ZK server to keep running on a machine that uses short-lived certs that refresh frequently without having to restart the ZK process. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3174 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/680.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #680 commit 2122c8c23a0dbb27f9b2aff55e800e48d253f943 Author: Ilya Maykov Date: 2018-10-25T00:41:48Z ZOOKEEPER-3173: Quorum TLS - support PEM trust/key stores ZOOKEEPER-3175: Quorum TLS - test improvements Add support for loading key and trust stores from PEM files. Also added test utils for testing X509-related code, because it was very difficult to untangle them from the PEM support code. commit 69f5185c8c14720e94c81f0147ee9cbc2ae42f89 Author: Ilya Maykov Date: 2018-10-25T01:22:24Z ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades commit d9e09dc73a42be079a6bd28b51c09635fff32e95 Author: Ilya Maykov Date: 2018-10-25T01:54:06Z ZOOKEEPER-3174: Quorum TLS - support reloading trust/key store ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/680 ---
[GitHub] zookeeper issue #678: ZOOKEEPER-3173: Quorum TLS - support PEM trust/key sto...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/678 @anmolnar is there a way to reproduce the exact same steps that jenkins runs on my macbook? ---
[GitHub] zookeeper issue #678: ZOOKEEPER-3173: Quorum TLS - support PEM trust/key sto...
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/678 @anmolnar it works for me as far as I can tell, I think the contbuild is flaky? The contbuild on #681, which includes the same commit, passes. ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
Github user ivmaykov closed the pull request at: https://github.com/apache/zookeeper/pull/679 ---
[GitHub] zookeeper pull request #679: ZOOKEEPER-3172: Quorum TLS - fix port unificati...
GitHub user ivmaykov reopened a pull request: https://github.com/apache/zookeeper/pull/679 ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades Fix numerous problems with UnifiedServerSocket, such as hanging the accept() thread when the client doesn't send any data or crashing if less than 5 bytes are read from the socket in the initial read. Re-enable the "portUnification" config option. Note that this is stacked on top of #678 and thus includes it. Please only consider the ZOOKEEPER-3172 commit when reviewing. Once the other PR is merged upstream, I will rebase this so it only contains one commit. ## Fixed networking issues/bugs in UnifiedServerSocket - don't crash the `accept()` thread if the client closes the connection without sending any data - don't corrupt the connection if the client sends fewer than 5 bytes for the initial read - delay the detection of TLS vs. plaintext mode until a socket stream is read from or written to. This prevents the `accept()` thread from getting blocked on a `read()` operation from the newly connected socket. - prepending 5 bytes to `PrependableSocket` and then trying to read >5 bytes would only return the first 5 bytes, even if more bytes were available. This is fixed. You can merge this pull request into a Git repository by running: $ git pull https://github.com/ivmaykov/zookeeper ZOOKEEPER-3172 Alternatively you can review and apply these changes as the patch at: https://github.com/apache/zookeeper/pull/679.patch To close this pull request, make a commit to your master/trunk branch with (at least) the following in the commit message: This closes #679 commit 2122c8c23a0dbb27f9b2aff55e800e48d253f943 Author: Ilya Maykov Date: 2018-10-25T00:41:48Z ZOOKEEPER-3173: Quorum TLS - support PEM trust/key stores ZOOKEEPER-3175: Quorum TLS - test improvements Add support for loading key and trust stores from PEM files. Also added test utils for testing X509-related code, because it was very difficult to untangle them from the PEM support code. commit 69f5185c8c14720e94c81f0147ee9cbc2ae42f89 Author: Ilya Maykov Date: 2018-10-25T01:22:24Z ZOOKEEPER-3172: Quorum TLS - fix port unification to allow rolling upgrades ---
[GitHub] zookeeper issue #669: ZOOKEEPER-3152: Port ZK netty stack to netty4
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/669 @maoling it will be hard to do perf comparison of netty3 vs netty4 for us because we are currently using the NIO transports, and we don't plan on switching to netty3 in production. Comparing NIO vs netty4 is kind of apples-and-oranges. A quick perf test with this patch showed that NIO to netty4 did not result in any obvious performance regressions, so I think we can say they are at least comparable :) ---
[GitHub] zookeeper issue #669: ZOOKEEPER-3152: Port ZK netty stack to netty4
Github user ivmaykov commented on the issue: https://github.com/apache/zookeeper/pull/669 Rebase, update localAddress after accepting connection and log it ---
[GitHub] zookeeper pull request #680: ZOOKEEPER-3174: Quorum TLS - support reloading ...
Github user ivmaykov commented on a diff in the pull request: https://github.com/apache/zookeeper/pull/680#discussion_r230574766 --- Diff: zookeeper-server/src/main/java/org/apache/zookeeper/common/FileChangeWatcher.java --- @@ -0,0 +1,191 @@ +/** + * 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.common; + +import com.sun.nio.file.SensitivityWatchEventModifier; +import org.apache.zookeeper.server.ZooKeeperThread; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; +import java.nio.file.ClosedWatchServiceException; +import java.nio.file.FileSystem; +import java.nio.file.Path; +import java.nio.file.StandardWatchEventKinds; +import java.nio.file.WatchEvent; +import java.nio.file.WatchKey; +import java.nio.file.WatchService; +import java.util.function.Consumer; + +/** + * Instances of this class can be used to watch a directory for file changes. When a file is added to, deleted from, + * or is modified in the given directory, the callback provided by the user will be called from a background thread. + * Some things to keep in mind: + * + * The callback should be thread-safe. + * Changes that happen around the time the thread is started may be missed. + * There is a delay between a file changing and the callback firing. + * The watch is not recursive - changes to subdirectories will not trigger a callback. + * + */ +public final class FileChangeWatcher { +private static final Logger LOG = LoggerFactory.getLogger(FileChangeWatcher.class); + +public enum State { +NEW, // object created but start() not called yet +STARTING, // start() called but background thread has not entered main loop +RUNNING, // background thread is running +STOPPING, // stop() called but background thread has not exited main loop +STOPPED // stop() called and background thread has exited, or background thread crashed +} + +private final WatcherThread watcherThread; +private State state; // protected by synchronized(this) + +/** + * Creates a watcher that watches dirPath and invokes callback on changes. + * + * @param dirPath the directory to watch. + * @param callback the callback to invoke with events. event.kind() will return the type of event, + * and event.context() will return the filename relative to dirPath. + * @throws IOException if there is an error creating the WatchService. + */ +public FileChangeWatcher(Path dirPath, Consumer> callback) throws IOException { +FileSystem fs = dirPath.getFileSystem(); +WatchService watchService = fs.newWatchService(); +if (LOG.isDebugEnabled()) { +LOG.debug("Registering with watch service: " + dirPath); +} +dirPath.register( +watchService, +new WatchEvent.Kind[]{ +StandardWatchEventKinds.ENTRY_CREATE, +StandardWatchEventKinds.ENTRY_DELETE, +StandardWatchEventKinds.ENTRY_MODIFY, +StandardWatchEventKinds.OVERFLOW}, +SensitivityWatchEventModifier.HIGH); +state = State.NEW; +this.watcherThread = new WatcherThread(watchService, callback); +this.watcherThread.setDaemon(true); +} + +public synchronized State getState() { --- End diff -- I agree, there are use cases where a R/W lock is a great choice, but I don't think this is one of them. ---