Skip to content

Commit 4b6bcea

Browse files
symatMate Szalay-Beko
authored andcommitted
ZOOKEEPER-3188: MultiAddress unit tests for Quorum TLS and Kerberos/Digest authentication
1 parent 40bc44c commit 4b6bcea

5 files changed

Lines changed: 163 additions & 16 deletions

File tree

zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/QuorumSSLTest.java

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,8 @@ private KeyPair createKeyPair() throws NoSuchProviderException, NoSuchAlgorithmE
378378
}
379379

380380
private String generateQuorumConfiguration() {
381+
StringBuilder sb = new StringBuilder();
382+
381383
int portQp1 = PortAssignment.unique();
382384
int portQp2 = PortAssignment.unique();
383385
int portQp3 = PortAssignment.unique();
@@ -386,9 +388,35 @@ private String generateQuorumConfiguration() {
386388
int portLe2 = PortAssignment.unique();
387389
int portLe3 = PortAssignment.unique();
388390

389-
return "server.1=127.0.0.1:" + (portQp1) + ":" + (portLe1) + ";" + clientPortQp1
390-
+ "\n" + "server.2=127.0.0.1:" + (portQp2) + ":" + (portLe2) + ";" + clientPortQp2
391-
+ "\n" + "server.3=127.0.0.1:" + (portQp3) + ":" + (portLe3) + ";" + clientPortQp3;
391+
sb.append(String.format("server.1=127.0.0.1:%d:%d;%d\n", portQp1, portLe1, clientPortQp1));
392+
sb.append(String.format("server.2=127.0.0.1:%d:%d;%d\n", portQp2, portLe2, clientPortQp2));
393+
sb.append(String.format("server.3=127.0.0.1:%d:%d;%d\n", portQp3, portLe3, clientPortQp3));
394+
395+
return sb.toString();
396+
}
397+
398+
private String generateMultiAddressQuorumConfiguration() {
399+
StringBuilder sb = new StringBuilder();
400+
401+
int portQp1a = PortAssignment.unique();
402+
int portQp1b = PortAssignment.unique();
403+
int portQp2a = PortAssignment.unique();
404+
int portQp2b = PortAssignment.unique();
405+
int portQp3a = PortAssignment.unique();
406+
int portQp3b = PortAssignment.unique();
407+
408+
int portLe1a = PortAssignment.unique();
409+
int portLe1b = PortAssignment.unique();
410+
int portLe2a = PortAssignment.unique();
411+
int portLe2b = PortAssignment.unique();
412+
int portLe3a = PortAssignment.unique();
413+
int portLe3b = PortAssignment.unique();
414+
415+
sb.append(String.format("server.1=127.0.0.1:%d:%d|127.0.0.1:%d:%d;%d\n", portQp1a, portLe1a, portQp1b, portLe1b, clientPortQp1));
416+
sb.append(String.format("server.2=127.0.0.1:%d:%d|127.0.0.1:%d:%d;%d\n", portQp2a, portLe2a, portQp2b, portLe2b, clientPortQp2));
417+
sb.append(String.format("server.3=127.0.0.1:%d:%d|127.0.0.1:%d:%d;%d\n", portQp3a, portLe3a, portQp3b, portLe3b, clientPortQp3));
418+
419+
return sb.toString();
392420
}
393421

394422
public void setSSLSystemProperties() {
@@ -449,6 +477,30 @@ public void testQuorumSSL() throws Exception {
449477
assertFalse(ClientBase.waitForServerUp("127.0.0.1:" + clientPortQp3, CONNECTION_TIMEOUT));
450478
}
451479

480+
481+
@Test
482+
public void testQuorumSSLWithMultipleAddresses() throws Exception {
483+
quorumConfiguration = generateMultiAddressQuorumConfiguration();
484+
485+
q1 = new MainThread(1, clientPortQp1, quorumConfiguration, SSL_QUORUM_ENABLED);
486+
q2 = new MainThread(2, clientPortQp2, quorumConfiguration, SSL_QUORUM_ENABLED);
487+
488+
q1.start();
489+
q2.start();
490+
491+
assertTrue(ClientBase.waitForServerUp("127.0.0.1:" + clientPortQp1, CONNECTION_TIMEOUT));
492+
assertTrue(ClientBase.waitForServerUp("127.0.0.1:" + clientPortQp2, CONNECTION_TIMEOUT));
493+
494+
clearSSLSystemProperties();
495+
496+
// This server should fail to join the quorum as it is not using ssl.
497+
q3 = new MainThread(3, clientPortQp3, quorumConfiguration);
498+
q3.start();
499+
500+
assertFalse(ClientBase.waitForServerUp("127.0.0.1:" + clientPortQp3, CONNECTION_TIMEOUT));
501+
}
502+
503+
452504
@Test
453505
public void testRollingUpgrade() throws Exception {
454506
// Form a quorum without ssl
@@ -544,6 +596,24 @@ public void testHostnameVerificationWithInvalidIpAddressAndInvalidHostname() thr
544596
testHostnameVerification(badhostnameKeystorePath, false);
545597
}
546598

599+
@Test
600+
public void testHostnameVerificationForInvalidMultiAddressServerConfig() throws Exception {
601+
quorumConfiguration = generateMultiAddressQuorumConfiguration();
602+
603+
String badhostnameKeystorePath = tmpDir + "/badhost.jks";
604+
X509Certificate badHostCert = buildEndEntityCert(
605+
defaultKeyPair,
606+
rootCertificate,
607+
rootKeyPair.getPrivate(),
608+
"bleepbloop",
609+
"140.211.11.105",
610+
null,
611+
null);
612+
writeKeystore(badHostCert, defaultKeyPair, badhostnameKeystorePath);
613+
614+
testHostnameVerification(badhostnameKeystorePath, false);
615+
}
616+
547617
@Test
548618
public void testHostnameVerificationWithInvalidIpAddressAndValidHostname() throws Exception {
549619
String badhostnameKeystorePath = tmpDir + "/badhost.jks";

zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/auth/QuorumAuthTestBase.java

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -64,12 +64,23 @@ public static void cleanupJaasConfig() {
6464
}
6565
}
6666

67+
protected String startQuorum(final int serverCount, Map<String, String> authConfigs,
68+
int authServerCount) throws IOException {
69+
return this.startQuorum(serverCount, authConfigs, authServerCount, false);
70+
}
71+
72+
protected String startMultiAddressQuorum(final int serverCount, Map<String, String> authConfigs,
73+
int authServerCount) throws IOException {
74+
return this.startQuorum(serverCount, authConfigs, authServerCount, true);
75+
}
76+
6777
protected String startQuorum(
6878
final int serverCount,
6979
Map<String, String> authConfigs,
70-
int authServerCount) throws IOException {
80+
int authServerCount,
81+
boolean multiAddress) throws IOException {
7182
StringBuilder connectStr = new StringBuilder();
72-
final int[] clientPorts = startQuorum(serverCount, connectStr, authConfigs, authServerCount);
83+
final int[] clientPorts = startQuorum(serverCount, connectStr, authConfigs, authServerCount, multiAddress);
7384
for (int i = 0; i < serverCount; i++) {
7485
assertTrue(
7586
"waiting for server " + i + " being up",
@@ -78,17 +89,17 @@ protected String startQuorum(
7889
return connectStr.toString();
7990
}
8091

81-
protected int[] startQuorum(
82-
final int serverCount,
83-
StringBuilder connectStr,
84-
Map<String, String> authConfigs,
85-
int authServerCount) throws IOException {
92+
protected int[] startQuorum(final int serverCount, StringBuilder connectStr, Map<String, String> authConfigs,
93+
int authServerCount, boolean multiAddress) throws IOException {
8694
final int[] clientPorts = new int[serverCount];
8795
StringBuilder sb = new StringBuilder();
8896
for (int i = 0; i < serverCount; i++) {
8997
clientPorts[i] = PortAssignment.unique();
90-
String server = String.format("server.%d=localhost:%d:%d:participant", i, PortAssignment.unique(), PortAssignment.unique());
91-
sb.append(server + "\n");
98+
String server = String.format("server.%d=localhost:%d:%d", i, PortAssignment.unique(), PortAssignment.unique());
99+
if (multiAddress) {
100+
server = server + String.format("|localhost:%d:%d", PortAssignment.unique(), PortAssignment.unique());
101+
}
102+
sb.append(server + ":participant\n");
92103
connectStr.append("127.0.0.1:" + clientPorts[i]);
93104
if (i < serverCount - 1) {
94105
connectStr.append(",");

zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/auth/QuorumDigestAuthTest.java

Lines changed: 22 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,27 @@ public void testValidCredentials() throws Exception {
9292
zk.close();
9393
}
9494

95+
/**
96+
* Test to verify that server is able to start with valid credentials
97+
* when using multiple Quorum / Election addresses
98+
*/
99+
@Test(timeout = 30000)
100+
public void testValidCredentialsWithMultiAddresses() throws Exception {
101+
Map<String, String> authConfigs = new HashMap<String, String>();
102+
authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "true");
103+
authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "true");
104+
authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, "true");
105+
106+
String connectStr = startMultiAddressQuorum(3, authConfigs, 3);
107+
CountdownWatcher watcher = new CountdownWatcher();
108+
ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT, watcher);
109+
watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);
110+
for (int i = 0; i < 10; i++) {
111+
zk.create("/" + i, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
112+
}
113+
zk.close();
114+
}
115+
95116
/**
96117
* Test to verify that server is able to start with invalid credentials if
97118
* the configuration is set to quorum.auth.serverRequireSasl=false.
@@ -126,7 +147,7 @@ public void testSaslRequiredInvalidCredentials() throws Exception {
126147
authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "true");
127148
authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, "true");
128149
int serverCount = 2;
129-
final int[] clientPorts = startQuorum(serverCount, new StringBuilder(), authConfigs, serverCount);
150+
final int[] clientPorts = startQuorum(serverCount, new StringBuilder(), authConfigs, serverCount, false);
130151
for (int i = 0; i < serverCount; i++) {
131152
boolean waitForServerUp = ClientBase.waitForServerUp("127.0.0.1:" + clientPorts[i], QuorumPeerTestBase.TIMEOUT);
132153
assertFalse("Shouldn't start server with invalid credentials", waitForServerUp);

zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/auth/QuorumKerberosAuthTest.java

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131
import org.apache.zookeeper.test.ClientBase.CountdownWatcher;
3232
import org.junit.After;
3333
import org.junit.AfterClass;
34-
import org.junit.Before;
34+
import org.junit.BeforeClass;
3535
import org.junit.Test;
3636

3737
public class QuorumKerberosAuthTest extends KerberosSecurityTestcase {
@@ -70,8 +70,8 @@ public class QuorumKerberosAuthTest extends KerberosSecurityTestcase {
7070
setupJaasConfig(jaasEntries);
7171
}
7272

73-
@Before
74-
public void setUp() throws Exception {
73+
@BeforeClass
74+
public static void setUp() throws Exception {
7575
// create keytab
7676
keytabFile = new File(KerberosTestUtils.getKeytabFile());
7777
String learnerPrincipal = KerberosTestUtils.getLearnerPrincipal();
@@ -119,4 +119,27 @@ public void testValidCredentials() throws Exception {
119119
zk.close();
120120
}
121121

122+
/**
123+
* Test to verify that server is able to start with valid credentials
124+
* when using multiple Quorum / Election addresses
125+
*/
126+
@Test(timeout = 120000)
127+
public void testValidCredentialsWithMultiAddresses() throws Exception {
128+
String serverPrincipal = KerberosTestUtils.getServerPrincipal();
129+
serverPrincipal = serverPrincipal.substring(0, serverPrincipal.lastIndexOf("@"));
130+
Map<String, String> authConfigs = new HashMap<String, String>();
131+
authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "true");
132+
authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "true");
133+
authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, "true");
134+
authConfigs.put(QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL, serverPrincipal);
135+
String connectStr = startMultiAddressQuorum(3, authConfigs, 3);
136+
CountdownWatcher watcher = new CountdownWatcher();
137+
ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT, watcher);
138+
watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);
139+
for (int i = 0; i < 10; i++) {
140+
zk.create("/" + i, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
141+
}
142+
zk.close();
143+
}
144+
122145
}

zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/auth/QuorumKerberosHostBasedAuthTest.java

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -142,6 +142,28 @@ public void testValidCredentials() throws Exception {
142142
zk.close();
143143
}
144144

145+
/**
146+
* Test to verify that server is able to start with valid credentials
147+
* when using multiple Quorum / Election addresses
148+
*/
149+
@Test(timeout = 120000)
150+
public void testValidCredentialsWithMultiAddresses() throws Exception {
151+
String serverPrincipal = hostServerPrincipal.substring(0, hostServerPrincipal.lastIndexOf("@"));
152+
Map<String, String> authConfigs = new HashMap<String, String>();
153+
authConfigs.put(QuorumAuth.QUORUM_SASL_AUTH_ENABLED, "true");
154+
authConfigs.put(QuorumAuth.QUORUM_SERVER_SASL_AUTH_REQUIRED, "true");
155+
authConfigs.put(QuorumAuth.QUORUM_LEARNER_SASL_AUTH_REQUIRED, "true");
156+
authConfigs.put(QuorumAuth.QUORUM_KERBEROS_SERVICE_PRINCIPAL, serverPrincipal);
157+
String connectStr = startMultiAddressQuorum(3, authConfigs, 3);
158+
CountdownWatcher watcher = new CountdownWatcher();
159+
ZooKeeper zk = new ZooKeeper(connectStr, ClientBase.CONNECTION_TIMEOUT, watcher);
160+
watcher.waitForConnected(ClientBase.CONNECTION_TIMEOUT);
161+
for (int i = 0; i < 10; i++) {
162+
zk.create("/" + i, new byte[0], Ids.OPEN_ACL_UNSAFE, CreateMode.PERSISTENT);
163+
}
164+
zk.close();
165+
}
166+
145167
/**
146168
* Test to verify that the bad server connection to the quorum should be rejected.
147169
*/

0 commit comments

Comments
 (0)