/** * 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.I0Itec.zkclient; import static org.assertj.core.api.Assertions.assertThat; import static org.junit.Assert.fail; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import javax.security.auth.login.Configuration; import org.I0Itec.zkclient.exception.ZkAuthFailedException; import org.I0Itec.zkclient.exception.ZkException; import org.I0Itec.zkclient.exception.ZkTimeoutException; import org.apache.log4j.Logger; import org.apache.zookeeper.ZooDefs.Ids; import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; public class SaslAuthenticatedTest { protected static final Logger LOG = Logger.getLogger(SaslAuthenticatedTest.class); static final String ZK_AUTH_PROVIDER = "zookeeper.authProvider.1"; static final String ZK_ALLOW_FAILED_SASL = "zookeeper.allowSaslFailedClients"; @Rule public TemporaryFolder _temporaryFolder = new TemporaryFolder(); private int _port = 4700; private ZkClient _client; private ZkServer _zkServer; private String _zkServerContextName = "Server"; private String _zkClientContextName = "Client"; private String _userSuperPasswd = "adminpasswd"; private String _userServerSide = "fpj"; private String _userClientSide = "fpj"; private String _userServerSidePasswd = "fpjsecret"; private String _userClientSidePasswd = "fpjsecret"; private String _zkModule = "org.apache.zookeeper.server.auth.DigestLoginModule"; private String createJaasFile() throws IOException { File jaasFile = _temporaryFolder.newFile("jaas.conf"); FileOutputStream jaasOutputStream = new java.io.FileOutputStream(jaasFile); jaasOutputStream.write(String.format("%s {\n\t%s required\n", _zkServerContextName, _zkModule).getBytes()); jaasOutputStream.write(String.format("\tuser_super=\"%s\"\n", _userSuperPasswd).getBytes()); jaasOutputStream.write(String.format("\tuser_%s=\"%s\";\n};\n\n", _userServerSide, _userServerSidePasswd).getBytes()); jaasOutputStream.write(String.format("%s {\n\t%s required\n", _zkClientContextName, _zkModule).getBytes()); jaasOutputStream.write(String.format("\tusername=\"%s\"\n", _userClientSide).getBytes()); jaasOutputStream.write(String.format("\tpassword=\"%s\";\n};", _userClientSidePasswd).getBytes()); jaasOutputStream.close(); return jaasFile.getAbsolutePath(); } @Before public void setUp() throws IOException { // Reset all variables used for the jaas login file _zkServerContextName = "Server"; _zkClientContextName = "Client"; _userSuperPasswd = "adminpasswd"; _userServerSide = "fpj"; _userClientSide = "fpj"; _userServerSidePasswd = "fpjsecret"; _userClientSidePasswd = "fpjsecret"; _zkModule = "org.apache.zookeeper.server.auth.DigestLoginModule"; } @After public void tearDown() { if (_client != null) { _client.close(); } if (_zkServer != null) { _zkServer.shutdown(); } System.clearProperty(ZK_AUTH_PROVIDER); System.clearProperty(ZkClient.JAVA_LOGIN_CONFIG_PARAM); Configuration.setConfiguration(null); } private void bootstrap() throws IOException { Configuration.setConfiguration(null); String jaasFileName = createJaasFile(); System.setProperty(ZK_AUTH_PROVIDER, "org.apache.zookeeper.server.auth.SASLAuthenticationProvider"); System.setProperty(ZkClient.JAVA_LOGIN_CONFIG_PARAM, jaasFileName); _zkServer = TestUtil.startZkServer(_temporaryFolder, _port); _client = _zkServer.getZkClient(); } private void bootstrapWithAuthFailure() throws IOException { _userServerSide = "otheruser"; bootstrap(); } /** * Tests that a connection authenticates successfully. * * @throws IOException */ @Test public void testConnection() throws IOException { bootstrap(); _client.createPersistent("/test", new byte[0], Ids.CREATOR_ALL_ACL); assertThat(_client.exists("/test")).isTrue(); } /** * Tests that ZkClient throws an exception in the case ZooKeeper keeps dropping the connection due to authentication * failures. * * @throws IOException */ @Test public void testAuthFailure() throws IOException { try { bootstrapWithAuthFailure(); fail("Expected to fail!"); } catch (ZkException e) { assertThat(e).isInstanceOf(ZkTimeoutException.class); } } /** * Tests that ZkClient spots the AuthFailed event in the case the property to allow failed SASL connections is * enabled. * * @throws IOException */ @Test public void testAuthFailure_AllowFailedSasl() throws IOException { System.setProperty(ZK_ALLOW_FAILED_SASL, "true"); try { bootstrapWithAuthFailure(); fail("Expected to fail!"); } catch (ZkException e) { assertThat(e).isInstanceOf(ZkAuthFailedException.class); } finally { System.clearProperty(ZK_ALLOW_FAILED_SASL); } } /** * Tests that ZkClient spots the AuthFailed event in the case the property to allow failed SASL connections is * enabled. * * @throws IOException */ @Test public void testAuthFailure_DisabledSasl() throws IOException { System.setProperty(ZkClient.ZK_SASL_CLIENT, "false"); try { bootstrapWithAuthFailure(); } finally { System.clearProperty(ZkClient.ZK_SASL_CLIENT); } } @Test public void testUnauthenticatedClient() throws IOException { ZkClient unauthed = null; try { bootstrap(); System.clearProperty(ZkClient.JAVA_LOGIN_CONFIG_PARAM); System.setProperty("zookeeper.sasl.client", "true"); unauthed = new ZkClient("localhost:" + _port, 6000); unauthed.createPersistent("/test", new byte[0], Ids.OPEN_ACL_UNSAFE); } finally { if (unauthed != null) { unauthed.close(); } } } @Test public void testNoZkJaasFile() throws IOException { try { _zkClientContextName = "OtherClient"; _zkServerContextName = "OtherServer"; bootstrap(); _client.createPersistent("/test", new byte[0], Ids.OPEN_ACL_UNSAFE); assertThat(_client.exists("/test")).isTrue(); } catch (ZkAuthFailedException e) { fail("Caught ZkAuthFailed exception and was not expecting it"); } } }