kezhuw commented on code in PR #2269: URL: https://github.com/apache/zookeeper/pull/2269#discussion_r2206535706
########## zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/QuorumPeer.java: ########## @@ -1176,12 +1184,96 @@ public void initialize() throws SaslException { } authServer = new SaslQuorumAuthServer(isQuorumServerSaslAuthRequired(), quorumServerLoginContext, authzHosts); authLearner = new SaslQuorumAuthLearner(isQuorumLearnerSaslAuthRequired(), quorumServicePrincipal, quorumLearnerLoginContext); + } else if (isSslQuorum()) { + try { + authServer = getSslQuorumAuthServer(); + authLearner = getSslQuorumAuthLearner(); + } catch (Exception e) { + LOG.error(e.getMessage(), e); + throw new SaslException(e.getMessage()); Review Comment: Should be a `IOException` ? I guess you may have to change some signatures. ########## zookeeper-server/src/test/java/org/apache/zookeeper/server/quorum/QuorumPeerAuthProviderTest.java: ########## @@ -0,0 +1,171 @@ +/* + * 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.server.quorum; + +import static org.junit.jupiter.api.Assertions.assertTrue; +import java.io.File; +import java.lang.reflect.Method; +import java.util.Properties; +import org.apache.zookeeper.common.QuorumX509Util; +import org.apache.zookeeper.server.quorum.auth.MockSSLQuorumAuthLearner; +import org.apache.zookeeper.server.quorum.auth.MockSslQuorumAuthServer; +import org.apache.zookeeper.server.quorum.auth.NullQuorumAuthLearner; +import org.apache.zookeeper.server.quorum.auth.NullQuorumAuthServer; +import org.apache.zookeeper.server.quorum.auth.QuorumAuth; +import org.apache.zookeeper.server.quorum.auth.QuorumAuthLearner; +import org.apache.zookeeper.server.quorum.auth.QuorumAuthServer; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for pluggable SSL quorum auth providers in {@link QuorumPeer}. + */ +public class QuorumPeerAuthProviderTest { + + private QuorumX509Util quorumX509Util; + + private static final String SSL_AUTH_PROVIDER_PROPERTY = + "zookeeper." + QuorumAuth.QUORUM_SSL_AUTHPROVIDER; + private static final String SSL_LEARNER_AUTH_PROVIDER_PROPERTY = + "zookeeper." + QuorumAuth.QUORUM_SSL_LEARNER_AUTHPROVIDER; + + @BeforeEach + public void setup() { + quorumX509Util = new QuorumX509Util(); + } + /** + * When sslAuthServerProvider is set to a custom provider, ensure it instantiates correctly. + */ + @Test + public void testCustomSslAuthServerProvider() throws Exception { + // Prepare config with custom server auth provider + QuorumPeerConfig config = new QuorumPeerConfig(); + Properties zkProp = getDefaultZKProperties(); + zkProp.setProperty("sslQuorum", "true"); + zkProp.setProperty(QuorumAuth.QUORUM_SSL_AUTHPROVIDER, + MockSslQuorumAuthServer.class.getName()); + config.parseProperties(zkProp); + + // Set on peer and invoke private method + QuorumPeer peer = new QuorumPeer(); + peer.setSslAuthServerProvider(config.getSslAuthServerProvider()); + QuorumAuthServer authServer = invokeGetSslQuorumAuthServer(peer); + + assertTrue(authServer instanceof MockSslQuorumAuthServer, + "Expected MockSSLQuorumAuthServer when provider is configured"); + } + + /** + * When sslAuthServerProvider is set via JVM system property + */ + @Test + public void testSslAuthServerProviderSystemProperty() throws Exception { + System.setProperty(SSL_AUTH_PROVIDER_PROPERTY, + MockSslQuorumAuthServer.class.getName()); + try { + QuorumPeer peer = new QuorumPeer(); + peer.setSslAuthServerProvider("some.invalid.Class"); + QuorumAuthServer authServer = invokeGetSslQuorumAuthServer(peer); + assertTrue(authServer instanceof MockSslQuorumAuthServer, + "Expected system property for server auth provider"); + } finally { + System.clearProperty(SSL_AUTH_PROVIDER_PROPERTY); + } + } + /** + * Without any provider configured, default should be NullQuorumAuthServer. + */ + @Test + public void testDefaultSslAuthServerProvider() throws Exception { + QuorumPeer peer = new QuorumPeer(); + QuorumAuthServer authServer = invokeGetSslQuorumAuthServer(peer); + assertTrue(authServer instanceof NullQuorumAuthServer, + "Expected NullQuorumAuthServer when no provider is configured"); + } + + /** + * When sslAuthLearnerProvider is set to a custom provider, ensure it instantiates correctly. + */ + @Test + public void testCustomSslAuthLearnerProvider() throws Exception { + QuorumPeerConfig config = new QuorumPeerConfig(); + Properties zkProp = getDefaultZKProperties(); + zkProp.setProperty("sslQuorum", "true"); + zkProp.setProperty(QuorumAuth.QUORUM_SSL_LEARNER_AUTHPROVIDER, + MockSSLQuorumAuthLearner.class.getName()); + config.parseProperties(zkProp); + + QuorumPeer peer = new QuorumPeer(); + peer.setSslAuthLearnerProvider(config.getSslAuthLearnerProvider()); + QuorumAuthLearner authLearner = invokeGetSslQuorumAuthLearner(peer); + + assertTrue(authLearner instanceof MockSSLQuorumAuthLearner, + "Expected MockSSLQuorumAuthLearner when learner provider is configured"); + } + + /** + * When sslAuthLearnerProvider is set via JVM system property + */ + @Test + public void testSslAuthLearnerProviderSystemProperty() throws Exception { + System.setProperty(SSL_LEARNER_AUTH_PROVIDER_PROPERTY, + MockSSLQuorumAuthLearner.class.getName()); + try { + QuorumPeer peer = new QuorumPeer(); + QuorumAuthLearner authLearner = invokeGetSslQuorumAuthLearner(peer); + Properties props = System.getProperties(); + props.forEach((key, value) -> System.out.println(key + " = " + value)); + + assertTrue(authLearner instanceof MockSSLQuorumAuthLearner, + "Expected system property for learner auth provider"); + } finally { + System.clearProperty(SSL_LEARNER_AUTH_PROVIDER_PROPERTY); + } + } + /** + * Without any learner provider configured, default should be NullQuorumAuthLearner. + */ + @Test + public void testDefaultSslAuthLearnerProvider() throws Exception { + QuorumPeer peer = new QuorumPeer(); + QuorumAuthLearner authLearner = invokeGetSslQuorumAuthLearner(peer); + assertTrue(authLearner instanceof NullQuorumAuthLearner, + "Expected NullQuorumAuthLearner when no learner provider is configured"); + } + + // Reflection helpers to access private methods + + private QuorumAuthServer invokeGetSslQuorumAuthServer(QuorumPeer peer) throws Exception { + Method m = QuorumPeer.class.getDeclaredMethod("getSslQuorumAuthServer"); Review Comment: I think what you should do here is reading the field `authServer` for assertion, its getter is `getQuorumAuthServer`. ########## zookeeper-server/src/main/java/org/apache/zookeeper/server/quorum/QuorumPeerConfig.java: ########## @@ -390,6 +393,10 @@ public void parseProperties(Properties zkProp) throws IOException, ConfigExcepti multiAddressReachabilityCheckEnabled = parseBoolean(key, value); } else if (key.equals("oraclePath")) { oraclePath = value; + } else if (key.equals(QuorumAuth.QUORUM_SSL_AUTHPROVIDER)) { + sslAuthServerProvider = value; + } else if (key.equals(QuorumAuth.QUORUM_SSL_LEARNER_AUTHPROVIDER)) { Review Comment: > but reading the server properties that way isn’t strictly necessary I guess ZooKeeper server was designed to own/occupy jvm. You may have to delete these tow options from `QuorumPeerConfig`, otherwise it will not propagate them as system properties. -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: notifications-unsubscr...@zookeeper.apache.org For queries about this service, please contact Infrastructure at: us...@infra.apache.org