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>
|
<artifactId>httpclient</artifactId>
|
||||||
<scope>compile</scope>
|
<scope>compile</scope>
|
||||||
</dependency>
|
</dependency>
|
||||||
|
<dependency>
|
||||||
|
<groupId>org.apache.directory.server</groupId>
|
||||||
|
<artifactId>apacheds-kerberos-codec</artifactId>
|
||||||
|
<version>2.0.0-M15</version>
|
||||||
|
<scope>compile</scope>
|
||||||
|
</dependency>
|
||||||
</dependencies>
|
</dependencies>
|
||||||
|
|
||||||
<build>
|
<build>
|
||||||
|
|
|
@ -17,18 +17,27 @@
|
||||||
*/
|
*/
|
||||||
package org.apache.hadoop.security.authentication.util;
|
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.Field;
|
||||||
import java.lang.reflect.InvocationTargetException;
|
import java.lang.reflect.InvocationTargetException;
|
||||||
import java.lang.reflect.Method;
|
import java.lang.reflect.Method;
|
||||||
import java.net.InetAddress;
|
import java.net.InetAddress;
|
||||||
import java.net.UnknownHostException;
|
import java.net.UnknownHostException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
import java.util.Locale;
|
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.GSSException;
|
||||||
import org.ietf.jgss.Oid;
|
import org.ietf.jgss.Oid;
|
||||||
|
|
||||||
import static org.apache.hadoop.util.PlatformName.IBM_JAVA;
|
|
||||||
|
|
||||||
public class KerberosUtil {
|
public class KerberosUtil {
|
||||||
|
|
||||||
/* Return the Kerberos login module name */
|
/* Return the Kerberos login module name */
|
||||||
|
@ -103,4 +112,48 @@ public class KerberosUtil {
|
||||||
// with uppercase characters.
|
// with uppercase characters.
|
||||||
return service + "/" + fqdn.toLowerCase(Locale.US);
|
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;
|
package org.apache.hadoop.security.authentication.util;
|
||||||
|
|
||||||
import org.junit.Assert;
|
import java.io.File;
|
||||||
|
|
||||||
import java.io.IOException;
|
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;
|
import org.junit.Test;
|
||||||
|
|
||||||
public class TestKerberosUtil {
|
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
|
@Test
|
||||||
public void testGetServerPrincipal() throws IOException {
|
public void testGetServerPrincipal() throws IOException {
|
||||||
|
@ -51,4 +77,84 @@ public class TestKerberosUtil {
|
||||||
service + "/" + testHost.toLowerCase(),
|
service + "/" + testHost.toLowerCase(),
|
||||||
KerberosUtil.getServicePrincipal(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.
|
HADOOP-10535. Make the retry numbers in ActiveStandbyElector configurable.
|
||||||
(jing9)
|
(jing9)
|
||||||
|
|
||||||
|
HADOOP-10322. Add ability to read principal names from a keytab.
|
||||||
|
(Benoy Antony and Daryn Sharp via kihwal)
|
||||||
|
|
||||||
OPTIMIZATIONS
|
OPTIMIZATIONS
|
||||||
|
|
||||||
BUG FIXES
|
BUG FIXES
|
||||||
|
|
Loading…
Reference in New Issue