/* * 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.ambari.server.api.rest; import static org.apache.ambari.server.KdcServerConnectionVerification.ConnectionProtocol.TCP; import static org.apache.ambari.server.KdcServerConnectionVerification.ConnectionProtocol.UDP; import static org.easymock.EasyMock.createNiceMock; import static org.easymock.EasyMock.createStrictMock; import static org.easymock.EasyMock.expect; import static org.easymock.EasyMock.replay; import static org.easymock.EasyMock.verify; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; import java.util.Properties; import org.apache.ambari.server.KdcServerConnectionVerification; import org.apache.ambari.server.configuration.Configuration; import org.apache.directory.kerberos.client.KdcConfig; import org.apache.directory.kerberos.client.KdcConnection; import org.apache.directory.kerberos.client.TgTicket; import org.apache.directory.shared.kerberos.KerberosMessageType; import org.apache.directory.shared.kerberos.exceptions.ErrorType; import org.apache.directory.shared.kerberos.exceptions.KerberosException; import org.apache.directory.shared.kerberos.messages.KrbError; import org.junit.Before; import org.junit.Ignore; import org.junit.Test; /** * Test for {@link KdcServerConnectionVerification} */ public class KdcServerConnectionVerificationTest { private Configuration configuration; private static final int KDC_TEST_PORT = 8090; @Before public void before() throws Exception { Properties configProps = new Properties(); configProps.setProperty(Configuration.KDC_PORT.getKey(), Integer.toString(KDC_TEST_PORT)); configuration = new Configuration(configProps); } @Test public void testValidate__Fail_InvalidPort() throws Exception { assertFalse(new KdcServerConnectionVerification(configuration).isKdcReachable("test-host:abcd")); } @Test public void testValidate__Success() throws Exception { KdcConnection connection = createStrictMock(KdcConnection.class); expect(connection.getTgt("noUser@noRealm", "noPassword")).andReturn(null).once(); replay(connection); TestKdcServerConnectionVerification kdcConnVerifier = new TestKdcServerConnectionVerification(configuration, connection); boolean result = kdcConnVerifier.isKdcReachable("test-host:11111"); assertTrue(result); KdcConfig kdcConfig = kdcConnVerifier.getConfigUsedInConnectionCreation(); assertEquals("test-host", kdcConfig.getHostName()); assertEquals(11111, kdcConfig.getKdcPort()); assertEquals(10 * 1000, kdcConfig.getTimeout()); verify(connection); } @Test public void testValidateTCP__Successful() throws Exception { KdcConnection connection = createStrictMock(KdcConnection.class); expect(connection.getTgt("noUser@noRealm", "noPassword")).andReturn(null).once(); replay(connection); TestKdcServerConnectionVerification kdcConnVerifier = new TestKdcServerConnectionVerification(configuration, connection); boolean result = kdcConnVerifier.isKdcReachable("test-host", 11111, TCP); assertTrue(result); KdcConfig kdcConfig = kdcConnVerifier.getConfigUsedInConnectionCreation(); assertFalse(kdcConfig.isUseUdp()); assertEquals("test-host", kdcConfig.getHostName()); assertEquals(11111, kdcConfig.getKdcPort()); assertEquals(10 * 1000, kdcConfig.getTimeout()); verify(connection); } @Test public void testValidateTCP__Successful2() throws Exception { KrbError error = createNiceMock(KrbError.class); expect(error.getErrorCode()).andReturn(ErrorType.KDC_ERR_C_PRINCIPAL_UNKNOWN).once(); expect(error.getMessageType()).andReturn(KerberosMessageType.KRB_ERROR).once(); KerberosException exception = createNiceMock(KerberosException.class); expect(exception.getError()).andReturn(error).once(); KdcConnection connection = createStrictMock(KdcConnection.class); expect(connection.getTgt("noUser@noRealm", "noPassword")).andThrow(exception); replay(connection, exception, error); TestKdcServerConnectionVerification kdcConnVerifier = new TestKdcServerConnectionVerification(configuration, connection); boolean result = kdcConnVerifier.isKdcReachable("test-host", 11111, TCP); assertTrue(result); KdcConfig kdcConfig = kdcConnVerifier.getConfigUsedInConnectionCreation(); assertFalse(kdcConfig.isUseUdp()); assertEquals("test-host", kdcConfig.getHostName()); assertEquals(11111, kdcConfig.getKdcPort()); assertEquals(10 * 1000, kdcConfig.getTimeout()); verify(connection, exception); } @Test public void testValidateTCP__Fail_UnknownException() throws Exception { KdcConnection connection = createStrictMock(KdcConnection.class); expect(connection.getTgt("noUser@noRealm", "noPassword")).andThrow( new RuntimeException("This is a really bad exception")); replay(connection); TestKdcServerConnectionVerification kdcConnVerifier = new TestKdcServerConnectionVerification(configuration, connection); boolean result = kdcConnVerifier.isKdcReachable("test-host", 11111, TCP); assertFalse(result); KdcConfig kdcConfig = kdcConnVerifier.getConfigUsedInConnectionCreation(); assertFalse(kdcConfig.isUseUdp()); assertEquals("test-host", kdcConfig.getHostName()); assertEquals(11111, kdcConfig.getKdcPort()); assertEquals(10 * 1000, kdcConfig.getTimeout()); verify(connection); } @Test public void testValidateTCP__Fail_Timeout() throws Exception { int timeout = 1; KdcConnection connection = new BlockingKdcConnection(null); TestKdcServerConnectionVerification kdcConnVerifier = new TestKdcServerConnectionVerification(configuration, connection); kdcConnVerifier.setConnectionTimeout(timeout); boolean result = kdcConnVerifier.isKdcReachable("test-host", 11111, TCP); assertFalse(result); KdcConfig kdcConfig = kdcConnVerifier.getConfigUsedInConnectionCreation(); assertFalse(kdcConfig.isUseUdp()); assertEquals("test-host", kdcConfig.getHostName()); assertEquals(11111, kdcConfig.getKdcPort()); assertEquals(timeout * 1000, kdcConfig.getTimeout()); } @Test public void testValidateTCP__Fail_TimeoutErrorCode() throws Exception { KdcConnection connection = createStrictMock(KdcConnection.class); expect(connection.getTgt("noUser@noRealm", "noPassword")).andThrow( new KerberosException(ErrorType.KRB_ERR_GENERIC, "TimeOut occurred")); replay(connection); TestKdcServerConnectionVerification kdcConnVerifier = new TestKdcServerConnectionVerification(configuration, connection); boolean result = kdcConnVerifier.isKdcReachable("test-host", 11111, TCP); assertFalse(result); KdcConfig kdcConfig = kdcConnVerifier.getConfigUsedInConnectionCreation(); assertFalse(kdcConfig.isUseUdp()); assertEquals("test-host", kdcConfig.getHostName()); assertEquals(11111, kdcConfig.getKdcPort()); assertEquals(10 * 1000, kdcConfig.getTimeout()); verify(connection); } @Test public void testValidateTCP__Fail_GeneralErrorCode_NotTimeout() throws Exception { KrbError error = createNiceMock(KrbError.class); expect(error.getErrorCode()).andReturn(ErrorType.KRB_ERR_GENERIC).once(); expect(error.getMessageType()).andReturn(KerberosMessageType.KRB_ERROR).once(); KerberosException exception = createNiceMock(KerberosException.class); expect(exception.getError()).andReturn(error).once(); KdcConnection connection = createStrictMock(KdcConnection.class); expect(connection.getTgt("noUser@noRealm", "noPassword")).andThrow(exception); replay(connection, exception, error); TestKdcServerConnectionVerification kdcConnVerifier = new TestKdcServerConnectionVerification(configuration, connection); boolean result = kdcConnVerifier.isKdcReachable("test-host", 11111, TCP); assertTrue(result); KdcConfig kdcConfig = kdcConnVerifier.getConfigUsedInConnectionCreation(); assertFalse(kdcConfig.isUseUdp()); assertEquals("test-host", kdcConfig.getHostName()); assertEquals(11111, kdcConfig.getKdcPort()); assertEquals(10 * 1000, kdcConfig.getTimeout()); verify(connection, exception); } @Test public void testValidateUDP__Successful() throws Exception { KdcConnection connection = createStrictMock(KdcConnection.class); expect(connection.getTgt("noUser@noRealm", "noPassword")).andReturn(null).once(); replay(connection); TestKdcServerConnectionVerification kdcConnVerifier = new TestKdcServerConnectionVerification(configuration, connection); boolean result = kdcConnVerifier.isKdcReachable("test-host", 11111, UDP); assertTrue(result); KdcConfig kdcConfig = kdcConnVerifier.getConfigUsedInConnectionCreation(); assertTrue(kdcConfig.isUseUdp()); assertEquals("test-host", kdcConfig.getHostName()); assertEquals(11111, kdcConfig.getKdcPort()); assertEquals(10 * 1000, kdcConfig.getTimeout()); verify(connection); } @Test public void testValidateUDP__Successful2() throws Exception { KrbError error = createNiceMock(KrbError.class); expect(error.getErrorCode()).andReturn(ErrorType.KDC_ERR_C_PRINCIPAL_UNKNOWN).once(); expect(error.getMessageType()).andReturn(KerberosMessageType.KRB_ERROR).once(); KerberosException exception = createNiceMock(KerberosException.class); expect(exception.getError()).andReturn(error).once(); KdcConnection connection = createStrictMock(KdcConnection.class); expect(connection.getTgt("noUser@noRealm", "noPassword")).andThrow(exception); replay(connection, exception, error); TestKdcServerConnectionVerification kdcConnVerifier = new TestKdcServerConnectionVerification(configuration, connection); boolean result = kdcConnVerifier.isKdcReachable("test-host", 11111, UDP); assertTrue(result); KdcConfig kdcConfig = kdcConnVerifier.getConfigUsedInConnectionCreation(); assertTrue(kdcConfig.isUseUdp()); assertEquals("test-host", kdcConfig.getHostName()); assertEquals(11111, kdcConfig.getKdcPort()); assertEquals(10 * 1000, kdcConfig.getTimeout()); verify(connection, exception); } @Test public void testValidateUDP__Fail_UnknownException() throws Exception { KdcConnection connection = createStrictMock(KdcConnection.class); expect(connection.getTgt("noUser@noRealm", "noPassword")).andThrow( new RuntimeException("This is a really bad exception")); replay(connection); TestKdcServerConnectionVerification kdcConnVerifier = new TestKdcServerConnectionVerification(configuration, connection); boolean result = kdcConnVerifier.isKdcReachable("test-host", 11111, UDP); assertFalse(result); KdcConfig kdcConfig = kdcConnVerifier.getConfigUsedInConnectionCreation(); assertTrue(kdcConfig.isUseUdp()); assertEquals("test-host", kdcConfig.getHostName()); assertEquals(11111, kdcConfig.getKdcPort()); assertEquals(10 * 1000, kdcConfig.getTimeout()); verify(connection); } @Test public void testValidateUDP__Fail_Timeout() throws Exception { int timeout = 1; KdcConnection connection = new BlockingKdcConnection(null); TestKdcServerConnectionVerification kdcConnVerifier = new TestKdcServerConnectionVerification(configuration, connection); kdcConnVerifier.setConnectionTimeout(timeout); boolean result = kdcConnVerifier.isKdcReachable("test-host", 11111, UDP); assertFalse(result); KdcConfig kdcConfig = kdcConnVerifier.getConfigUsedInConnectionCreation(); assertTrue(kdcConfig.isUseUdp()); assertEquals("test-host", kdcConfig.getHostName()); assertEquals(11111, kdcConfig.getKdcPort()); assertEquals(timeout * 1000, kdcConfig.getTimeout()); } @Test public void testValidateUDP__Fail_TimeoutErrorCode() throws Exception { KdcConnection connection = createStrictMock(KdcConnection.class); expect(connection.getTgt("noUser@noRealm", "noPassword")).andThrow( new KerberosException(ErrorType.KRB_ERR_GENERIC, "TimeOut occurred")); replay(connection); TestKdcServerConnectionVerification kdcConnVerifier = new TestKdcServerConnectionVerification(configuration, connection); boolean result = kdcConnVerifier.isKdcReachable("test-host", 11111, UDP); assertFalse(result); KdcConfig kdcConfig = kdcConnVerifier.getConfigUsedInConnectionCreation(); assertTrue(kdcConfig.isUseUdp()); assertEquals("test-host", kdcConfig.getHostName()); assertEquals(11111, kdcConfig.getKdcPort()); assertEquals(10 * 1000, kdcConfig.getTimeout()); verify(connection); } @Test public void testValidateUDP__Fail_GeneralErrorCode_NotTimeout() throws Exception { KrbError error = createNiceMock(KrbError.class); expect(error.getErrorCode()).andReturn(ErrorType.KRB_ERR_GENERIC).once(); expect(error.getMessageType()).andReturn(KerberosMessageType.KRB_ERROR).once(); KerberosException exception = createNiceMock(KerberosException.class); expect(exception.getError()).andReturn(error).once(); KdcConnection connection = createStrictMock(KdcConnection.class); expect(connection.getTgt("noUser@noRealm", "noPassword")).andThrow(exception); replay(connection, exception, error); TestKdcServerConnectionVerification kdcConnVerifier = new TestKdcServerConnectionVerification(configuration, connection); boolean result = kdcConnVerifier.isKdcReachable("test-host", 11111, UDP); assertTrue(result); KdcConfig kdcConfig = kdcConnVerifier.getConfigUsedInConnectionCreation(); assertTrue(kdcConfig.isUseUdp()); assertEquals("test-host", kdcConfig.getHostName()); assertEquals(11111, kdcConfig.getKdcPort()); assertEquals(10 * 1000, kdcConfig.getTimeout()); verify(connection, exception); } @Test @Ignore public void testValidate__Live() throws Exception { KdcServerConnectionVerification kdcConnVerifier = new KdcServerConnectionVerification(configuration); boolean result = kdcConnVerifier.isKdcReachable("c6501:88"); assertTrue(result); } // Test implementation which allows a mock KDC connection to be used. private static class TestKdcServerConnectionVerification extends KdcServerConnectionVerification { private KdcConnection connection; private KdcConfig kdcConfig = null; public TestKdcServerConnectionVerification(Configuration config, KdcConnection connectionMock) { super(config); connection = connectionMock; } @Override protected KdcConnection getKdcConnection(KdcConfig config) { kdcConfig = config; return connection; } public KdcConfig getConfigUsedInConnectionCreation() { return kdcConfig; } } /** * Test implementation which blocks on getTgt() for 60 seconds to facilitate timeout testing. */ private static class BlockingKdcConnection extends KdcConnection { public BlockingKdcConnection(KdcConfig config) { super(config); } @Override public TgTicket getTgt(String principal, String password) throws Exception { // although it is generally a bad idea to use sleep in a unit test for a // timing mechanism, this is being used to simulate a timeout and should be // generally safe as we are not relying on this for timing other than expecting // that this will block longer than the timeout set on the connection validator // which should be set to 1 second when using this implementation. // We will only block the full 60 seconds in the case of a specific test failure // where the callable doesn't properly set the timeout on the get. Thread.sleep(60000); return null; } } }