/* * 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.serveraction.kerberos; import java.io.File; import java.io.FileInputStream; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.ambari.server.security.credential.PrincipalKeyCredential; import org.apache.commons.codec.binary.Base64; import org.apache.directory.server.kerberos.shared.keytab.Keytab; import org.apache.directory.server.kerberos.shared.keytab.KeytabEntry; import org.apache.directory.shared.kerberos.codec.types.EncryptionType; import org.easymock.EasyMockSupport; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import junit.framework.Assert; public abstract class KerberosOperationHandlerTest extends EasyMockSupport { @Rule public TemporaryFolder folder = new TemporaryFolder(); @Test public void testCreateKeytabFileOneAtATime() throws Exception { KerberosOperationHandler handler = createHandler(); File file = folder.newFile(); final String principal1 = "principal1@REALM.COM"; final String principal2 = "principal2@REALM.COM"; int count; Assert.assertTrue(handler.createKeytabFile(principal1, "some password", 0, file)); Keytab keytab = Keytab.read(file); Assert.assertNotNull(keytab); List<KeytabEntry> entries = keytab.getEntries(); Assert.assertNotNull(entries); Assert.assertFalse(entries.isEmpty()); count = entries.size(); for (KeytabEntry entry : entries) { Assert.assertEquals(principal1, entry.getPrincipalName()); } Assert.assertTrue(handler.createKeytabFile(principal2, "some password", 0, file)); keytab = Keytab.read(file); Assert.assertNotNull(keytab); entries = keytab.getEntries(); Assert.assertNotNull(entries); Assert.assertFalse(entries.isEmpty()); Assert.assertEquals(count * 2, entries.size()); } @Test public void testEnsureKeytabFileContainsNoDuplicates() throws Exception { KerberosOperationHandler handler = createHandler(); File file = folder.newFile(); final String principal1 = "principal1@REALM.COM"; final String principal2 = "principal2@REALM.COM"; Set<String> seenEntries = new HashSet<>(); Assert.assertTrue(handler.createKeytabFile(principal1, "some password", 0, file)); Assert.assertTrue(handler.createKeytabFile(principal2, "some password", 0, file)); // Attempt to add duplicate entries Assert.assertTrue(handler.createKeytabFile(principal2, "some password", 0, file)); Keytab keytab = Keytab.read(file); Assert.assertNotNull(keytab); List<KeytabEntry> entries = keytab.getEntries(); Assert.assertNotNull(entries); Assert.assertFalse(entries.isEmpty()); for (KeytabEntry entry : entries) { String seenEntry = String.format("%s|%s", entry.getPrincipalName(), entry.getKey().getKeyType().toString()); Assert.assertFalse(seenEntries.contains(seenEntry)); seenEntries.add(seenEntry); } } @Test public void testCreateKeytabFileExceptions() throws Exception { KerberosOperationHandler handler = createHandler(); File file = folder.newFile(); final String principal1 = "principal1@REALM.COM"; try { handler.createKeytabFile(null, "some password", 0, file); Assert.fail("KerberosOperationException not thrown with null principal"); } catch (Throwable t) { Assert.assertEquals(KerberosOperationException.class, t.getClass()); } try { handler.createKeytabFile(principal1, null, null, file); Assert.fail("KerberosOperationException not thrown with null password"); } catch (Throwable t) { Assert.assertEquals(KerberosOperationException.class, t.getClass()); } try { handler.createKeytabFile(principal1, "some password", 0, null); Assert.fail("KerberosOperationException not thrown with null file"); } catch (Throwable t) { Assert.assertEquals(KerberosOperationException.class, t.getClass()); } } @Test public void testCreateKeytabFileFromBase64EncodedData() throws Exception { KerberosOperationHandler handler = createHandler(); File file = folder.newFile(); final String principal = "principal@REALM.COM"; Assert.assertTrue(handler.createKeytabFile(principal, "some password", 0, file)); FileInputStream fis = new FileInputStream(file); byte[] data = new byte[(int) file.length()]; Assert.assertEquals(data.length, fis.read(data)); fis.close(); File f = handler.createKeytabFile(Base64.encodeBase64String(data)); if (f != null) { try { Keytab keytab = Keytab.read(f); Assert.assertNotNull(keytab); List<KeytabEntry> entries = keytab.getEntries(); Assert.assertNotNull(entries); Assert.assertFalse(entries.isEmpty()); for (KeytabEntry entry : entries) { Assert.assertEquals(principal, entry.getPrincipalName()); } } finally { if (!f.delete()) { f.deleteOnExit(); } } } } @Test public void testMergeKeytabs() throws KerberosOperationException { KerberosOperationHandler handler = createHandler(); Keytab keytab1 = handler.createKeytab("principal@EXAMPLE.COM", "password", 1); Keytab keytab2 = handler.createKeytab("principal@EXAMPLE.COM", "password1", 1); Keytab keytab3 = handler.createKeytab("principal1@EXAMPLE.COM", "password", 4); Keytab merged; merged = handler.mergeKeytabs(keytab1, keytab2); Assert.assertEquals(keytab1.getEntries().size(), merged.getEntries().size()); merged = handler.mergeKeytabs(keytab1, keytab3); Assert.assertEquals(keytab1.getEntries().size() + keytab3.getEntries().size(), merged.getEntries().size()); merged = handler.mergeKeytabs(keytab2, keytab3); Assert.assertEquals(keytab2.getEntries().size() + keytab3.getEntries().size(), merged.getEntries().size()); merged = handler.mergeKeytabs(keytab2, merged); Assert.assertEquals(keytab2.getEntries().size() + keytab3.getEntries().size(), merged.getEntries().size()); } @Test public void testTranslateEncryptionTypes() throws Exception { KerberosOperationHandler handler = createHandler(); Assert.assertEquals( new HashSet<EncryptionType>() {{ add(EncryptionType.AES256_CTS_HMAC_SHA1_96); add(EncryptionType.AES128_CTS_HMAC_SHA1_96); add(EncryptionType.DES3_CBC_SHA1_KD); add(EncryptionType.DES_CBC_MD5); add(EncryptionType.DES_CBC_MD4); add(EncryptionType.DES_CBC_CRC); add(EncryptionType.UNKNOWN); }}, handler.translateEncryptionTypes("aes256-cts-hmac-sha1-96\n aes128-cts-hmac-sha1-96\tdes3-cbc-sha1 arcfour-hmac-md5 " + "camellia256-cts-cmac camellia128-cts-cmac des-cbc-crc des-cbc-md5 des-cbc-md4", "\\s+") ); Assert.assertEquals( new HashSet<EncryptionType>() {{ add(EncryptionType.AES256_CTS_HMAC_SHA1_96); add(EncryptionType.AES128_CTS_HMAC_SHA1_96); }}, handler.translateEncryptionTypes("aes", " ") ); Assert.assertEquals( new HashSet<EncryptionType>() {{ add(EncryptionType.AES256_CTS_HMAC_SHA1_96); }}, handler.translateEncryptionTypes("aes-256", " ") ); Assert.assertEquals( new HashSet<EncryptionType>() {{ add(EncryptionType.DES3_CBC_SHA1_KD); }}, handler.translateEncryptionTypes("des3", " ") ); } @Test public void testEscapeCharacters() throws KerberosOperationException { KerberosOperationHandler handler = createHandler(); HashSet<Character> specialCharacters = new HashSet<Character>() { { add('/'); add(','); add('\\'); add('#'); add('+'); add('<'); add('>'); add(';'); add('"'); add('='); add(' '); } }; Assert.assertEquals("\\/\\,\\\\\\#\\+\\<\\>\\;\\\"\\=\\ ", handler.escapeCharacters("/,\\#+<>;\"= ", specialCharacters, '\\')); Assert.assertNull(handler.escapeCharacters(null, specialCharacters, '\\')); Assert.assertEquals("", handler.escapeCharacters("", specialCharacters, '\\')); Assert.assertEquals("nothing_special_here", handler.escapeCharacters("nothing_special_here", specialCharacters, '\\')); Assert.assertEquals("\\/\\,\\\\\\#\\+\\<\\>\\;\\\"\\=\\ ", handler.escapeCharacters("/,\\#+<>;\"= ", specialCharacters, '\\')); Assert.assertEquals("nothing<>special#here!", handler.escapeCharacters("nothing<>special#here!", null, '\\')); Assert.assertEquals("nothing<>special#here!", handler.escapeCharacters("nothing<>special#here!", Collections.<Character>emptySet(), '\\')); Assert.assertEquals("nothing<>special#here!", handler.escapeCharacters("nothing<>special#here!", Collections.singleton('?'), '\\')); Assert.assertEquals("\\A's are special!", handler.escapeCharacters("A's are special!", Collections.singleton('A'), '\\')); } @Test(expected = KerberosAdminAuthenticationException.class) public void testAdminCredentialsNullPrincipal() throws KerberosOperationException { KerberosOperationHandler handler = createHandler(); PrincipalKeyCredential credentials = new PrincipalKeyCredential(null, "password"); handler.setAdministratorCredential(credentials); } @Test(expected = KerberosAdminAuthenticationException.class) public void testAdminCredentialsEmptyPrincipal() throws KerberosOperationException { KerberosOperationHandler handler = createHandler(); PrincipalKeyCredential credentials = new PrincipalKeyCredential("", "password"); handler.setAdministratorCredential(credentials); } @Test(expected = KerberosAdminAuthenticationException.class) public void testAdminCredentialsNullCredential() throws KerberosOperationException { KerberosOperationHandler handler = createHandler(); PrincipalKeyCredential credentials = new PrincipalKeyCredential("principal", (char[])null); handler.setAdministratorCredential(credentials); } @Test(expected = KerberosAdminAuthenticationException.class) public void testAdminCredentialsEmptyCredential1() throws KerberosOperationException { KerberosOperationHandler handler = createHandler(); PrincipalKeyCredential credentials = new PrincipalKeyCredential("principal", ""); handler.setAdministratorCredential(credentials); } @Test public void testSetExecutableSearchPaths() throws KerberosOperationException { KerberosOperationHandler handler = createHandler(); handler.setExecutableSearchPaths((String)null); Assert.assertNull(handler.getExecutableSearchPaths()); handler.setExecutableSearchPaths((String[])null); Assert.assertNull(handler.getExecutableSearchPaths()); handler.setExecutableSearchPaths(""); Assert.assertNotNull(handler.getExecutableSearchPaths()); Assert.assertEquals(0, handler.getExecutableSearchPaths().length); handler.setExecutableSearchPaths(new String[0]); Assert.assertNotNull(handler.getExecutableSearchPaths()); Assert.assertEquals(0, handler.getExecutableSearchPaths().length); handler.setExecutableSearchPaths(new String[]{""}); Assert.assertNotNull(handler.getExecutableSearchPaths()); Assert.assertEquals(1, handler.getExecutableSearchPaths().length); handler.setExecutableSearchPaths("/path1, path2, path3/"); Assert.assertNotNull(handler.getExecutableSearchPaths()); Assert.assertEquals(3, handler.getExecutableSearchPaths().length); Assert.assertEquals("/path1", handler.getExecutableSearchPaths()[0]); Assert.assertEquals("path2", handler.getExecutableSearchPaths()[1]); Assert.assertEquals("path3/", handler.getExecutableSearchPaths()[2]); handler.setExecutableSearchPaths("/path1, path2, ,path3/"); Assert.assertNotNull(handler.getExecutableSearchPaths()); Assert.assertEquals(3, handler.getExecutableSearchPaths().length); Assert.assertEquals("/path1", handler.getExecutableSearchPaths()[0]); Assert.assertEquals("path2", handler.getExecutableSearchPaths()[1]); Assert.assertEquals("path3/", handler.getExecutableSearchPaths()[2]); handler.setExecutableSearchPaths(new String[]{"/path1", "path2", "path3/"}); Assert.assertNotNull(handler.getExecutableSearchPaths()); Assert.assertEquals(3, handler.getExecutableSearchPaths().length); Assert.assertEquals("/path1", handler.getExecutableSearchPaths()[0]); Assert.assertEquals("path2", handler.getExecutableSearchPaths()[1]); Assert.assertEquals("path3/", handler.getExecutableSearchPaths()[2]); } private KerberosOperationHandler createHandler() throws KerberosOperationException { KerberosOperationHandler handler = new KerberosOperationHandler() { @Override public void open(PrincipalKeyCredential administratorCredentials, String defaultRealm, Map<String, String> kerberosConfiguration) throws KerberosOperationException { setAdministratorCredential(administratorCredentials); setDefaultRealm(defaultRealm); setExecutableSearchPaths("/usr/bin, /usr/kerberos/bin, /usr/sbin"); } @Override public void close() throws KerberosOperationException { } @Override public boolean principalExists(String principal) throws KerberosOperationException { return false; } @Override public Integer createPrincipal(String principal, String password, boolean service) throws KerberosOperationException { return 0; } @Override public Integer setPrincipalPassword(String principal, String password) throws KerberosOperationException { return 0; } @Override public boolean removePrincipal(String principal) throws KerberosOperationException { return false; } }; handler.open(new PrincipalKeyCredential("admin/admin", "hadoop"), "EXAMPLE.COM", null); return handler; } }