HADOOP-10322. Add ability to read principal names from a keytab. Contributed by Benoy Antony and Daryn Sharp.
git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1590637 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
parent
39abe66822
commit
295b58bb99
|
@ -97,6 +97,12 @@
|
|||
<artifactId>httpclient</artifactId>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>org.apache.directory.server</groupId>
|
||||
<artifactId>apacheds-kerberos-codec</artifactId>
|
||||
<version>2.0.0-M15</version>
|
||||
<scope>compile</scope>
|
||||
</dependency>
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -17,18 +17,27 @@
|
|||
*/
|
||||
package org.apache.hadoop.security.authentication.util;
|
||||
|
||||
import static org.apache.hadoop.util.PlatformName.IBM_JAVA;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.InetAddress;
|
||||
import java.net.UnknownHostException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Set;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.directory.server.kerberos.shared.keytab.Keytab;
|
||||
import org.apache.directory.server.kerberos.shared.keytab.KeytabEntry;
|
||||
import org.ietf.jgss.GSSException;
|
||||
import org.ietf.jgss.Oid;
|
||||
|
||||
import static org.apache.hadoop.util.PlatformName.IBM_JAVA;
|
||||
|
||||
public class KerberosUtil {
|
||||
|
||||
/* Return the Kerberos login module name */
|
||||
|
@ -103,4 +112,48 @@ public class KerberosUtil {
|
|||
// with uppercase characters.
|
||||
return service + "/" + fqdn.toLowerCase(Locale.US);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the unique principals present in the keytabfile.
|
||||
*
|
||||
* @param keytabFileName
|
||||
* Name of the keytab file to be read.
|
||||
* @return list of unique principals in the keytab.
|
||||
* @throws IOException
|
||||
* If keytab entries cannot be read from the file.
|
||||
*/
|
||||
static final String[] getPrincipalNames(String keytabFileName) throws IOException {
|
||||
Keytab keytab = Keytab.read(new File(keytabFileName));
|
||||
Set<String> principals = new HashSet<String>();
|
||||
List<KeytabEntry> entries = keytab.getEntries();
|
||||
for (KeytabEntry entry: entries){
|
||||
principals.add(entry.getPrincipalName().replace("\\", "/"));
|
||||
}
|
||||
return principals.toArray(new String[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all the unique principals from keytabfile which matches a pattern.
|
||||
*
|
||||
* @param keytab
|
||||
* Name of the keytab file to be read.
|
||||
* @param pattern
|
||||
* pattern to be matched.
|
||||
* @return list of unique principals which matches the pattern.
|
||||
* @throws IOException
|
||||
*/
|
||||
public static final String[] getPrincipalNames(String keytab,
|
||||
Pattern pattern) throws IOException {
|
||||
String[] principals = getPrincipalNames(keytab);
|
||||
if (principals.length != 0) {
|
||||
List<String> matchingPrincipals = new ArrayList<String>();
|
||||
for (String principal : principals) {
|
||||
if (pattern.matcher(principal).matches()) {
|
||||
matchingPrincipals.add(principal);
|
||||
}
|
||||
}
|
||||
principals = matchingPrincipals.toArray(new String[0]);
|
||||
}
|
||||
return principals;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -16,13 +16,39 @@
|
|||
*/
|
||||
package org.apache.hadoop.security.authentication.util;
|
||||
|
||||
import org.junit.Assert;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
import org.apache.directory.server.kerberos.shared.keytab.Keytab;
|
||||
import org.apache.directory.server.kerberos.shared.keytab.KeytabEntry;
|
||||
import org.apache.directory.shared.kerberos.KerberosTime;
|
||||
import org.apache.directory.shared.kerberos.codec.types.EncryptionType;
|
||||
import org.apache.directory.shared.kerberos.components.EncryptionKey;
|
||||
import org.junit.After;
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class TestKerberosUtil {
|
||||
static String testKeytab = "test.keytab";
|
||||
static String[] testPrincipals = new String[]{
|
||||
"HTTP@testRealm",
|
||||
"test/testhost@testRealm",
|
||||
"HTTP/testhost@testRealm",
|
||||
"HTTP1/testhost@testRealm",
|
||||
"HTTP/testhostanother@testRealm"
|
||||
};
|
||||
|
||||
@After
|
||||
public void deleteKeytab() {
|
||||
File keytabFile = new File(testKeytab);
|
||||
if (keytabFile.exists()){
|
||||
keytabFile.delete();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetServerPrincipal() throws IOException {
|
||||
|
@ -51,4 +77,84 @@ public class TestKerberosUtil {
|
|||
service + "/" + testHost.toLowerCase(),
|
||||
KerberosUtil.getServicePrincipal(service, testHost.toLowerCase()));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPrincipalNamesMissingKeytab() {
|
||||
try {
|
||||
KerberosUtil.getPrincipalNames(testKeytab);
|
||||
Assert.fail("Exception should have been thrown");
|
||||
} catch (IOException e) {
|
||||
//expects exception
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPrincipalNamesMissingPattern() throws IOException {
|
||||
createKeyTab(testKeytab, new String[]{"test/testhost@testRealm"});
|
||||
try {
|
||||
KerberosUtil.getPrincipalNames(testKeytab, null);
|
||||
Assert.fail("Exception should have been thrown");
|
||||
} catch (Exception e) {
|
||||
//expects exception
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPrincipalNamesFromKeytab() throws IOException {
|
||||
createKeyTab(testKeytab, testPrincipals);
|
||||
// read all principals in the keytab file
|
||||
String[] principals = KerberosUtil.getPrincipalNames(testKeytab);
|
||||
Assert.assertNotNull("principals cannot be null", principals);
|
||||
|
||||
int expectedSize = 0;
|
||||
List<String> principalList = Arrays.asList(principals);
|
||||
for (String principal : testPrincipals) {
|
||||
Assert.assertTrue("missing principal "+principal,
|
||||
principalList.contains(principal));
|
||||
expectedSize++;
|
||||
}
|
||||
Assert.assertEquals(expectedSize, principals.length);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testGetPrincipalNamesFromKeytabWithPattern() throws IOException {
|
||||
createKeyTab(testKeytab, testPrincipals);
|
||||
// read the keytab file
|
||||
// look for principals with HTTP as the first part
|
||||
Pattern httpPattern = Pattern.compile("HTTP/.*");
|
||||
String[] httpPrincipals =
|
||||
KerberosUtil.getPrincipalNames(testKeytab, httpPattern);
|
||||
Assert.assertNotNull("principals cannot be null", httpPrincipals);
|
||||
|
||||
int expectedSize = 0;
|
||||
List<String> httpPrincipalList = Arrays.asList(httpPrincipals);
|
||||
for (String principal : testPrincipals) {
|
||||
if (httpPattern.matcher(principal).matches()) {
|
||||
Assert.assertTrue("missing principal "+principal,
|
||||
httpPrincipalList.contains(principal));
|
||||
expectedSize++;
|
||||
}
|
||||
}
|
||||
Assert.assertEquals(expectedSize, httpPrincipals.length);
|
||||
}
|
||||
|
||||
private void createKeyTab(String fileName, String[] principalNames)
|
||||
throws IOException {
|
||||
//create a test keytab file
|
||||
List<KeytabEntry> lstEntries = new ArrayList<KeytabEntry>();
|
||||
for (String principal : principalNames){
|
||||
// create 3 versions of the key to ensure methods don't return
|
||||
// duplicate principals
|
||||
for (int kvno=1; kvno <= 3; kvno++) {
|
||||
EncryptionKey key = new EncryptionKey(
|
||||
EncryptionType.UNKNOWN, "samplekey1".getBytes(), kvno);
|
||||
KeytabEntry keytabEntry = new KeytabEntry(
|
||||
principal, 1 , new KerberosTime(), (byte) 1, key);
|
||||
lstEntries.add(keytabEntry);
|
||||
}
|
||||
}
|
||||
Keytab keytab = Keytab.getInstance();
|
||||
keytab.setEntries(lstEntries);
|
||||
keytab.write(new File(testKeytab));
|
||||
}
|
||||
}
|
|
@ -358,6 +358,9 @@ Release 2.5.0 - UNRELEASED
|
|||
HADOOP-10535. Make the retry numbers in ActiveStandbyElector configurable.
|
||||
(jing9)
|
||||
|
||||
HADOOP-10322. Add ability to read principal names from a keytab.
|
||||
(Benoy Antony and Daryn Sharp via kihwal)
|
||||
|
||||
OPTIMIZATIONS
|
||||
|
||||
BUG FIXES
|
||||
|
|
Loading…
Reference in New Issue