HADOOP-10698. KMS, add proxyuser support. (tucu)

git-svn-id: https://svn.apache.org/repos/asf/hadoop/common/trunk@1618217 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Alejandro Abdelnur 2014-08-15 15:53:28 +00:00
parent 7360cec692
commit e932365d6d
5 changed files with 230 additions and 50 deletions

View File

@ -210,6 +210,8 @@ Trunk (Unreleased)
HADOOP-10770. KMS add delegation token support. (tucu) HADOOP-10770. KMS add delegation token support. (tucu)
HADOOP-10698. KMS, add proxyuser support. (tucu)
BUG FIXES BUG FIXES
HADOOP-9451. Fault single-layer config if node group topology is enabled. HADOOP-9451. Fault single-layer config if node group topology is enabled.

View File

@ -28,6 +28,7 @@ import org.apache.hadoop.fs.CommonConfigurationKeysPublic;
import org.apache.hadoop.fs.Path; import org.apache.hadoop.fs.Path;
import org.apache.hadoop.security.Credentials; import org.apache.hadoop.security.Credentials;
import org.apache.hadoop.security.ProviderUtils; import org.apache.hadoop.security.ProviderUtils;
import org.apache.hadoop.security.UserGroupInformation;
import org.apache.hadoop.security.authentication.client.AuthenticationException; import org.apache.hadoop.security.authentication.client.AuthenticationException;
import org.apache.hadoop.security.authentication.client.ConnectionConfigurator; import org.apache.hadoop.security.authentication.client.ConnectionConfigurator;
import org.apache.hadoop.security.ssl.SSLFactory; import org.apache.hadoop.security.ssl.SSLFactory;
@ -52,6 +53,7 @@ import java.net.URL;
import java.net.URLEncoder; import java.net.URLEncoder;
import java.security.GeneralSecurityException; import java.security.GeneralSecurityException;
import java.security.NoSuchAlgorithmException; import java.security.NoSuchAlgorithmException;
import java.security.PrivilegedExceptionAction;
import java.text.MessageFormat; import java.text.MessageFormat;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Date; import java.util.Date;
@ -235,6 +237,7 @@ public class KMSClientProvider extends KeyProvider implements CryptoExtension,
private SSLFactory sslFactory; private SSLFactory sslFactory;
private ConnectionConfigurator configurator; private ConnectionConfigurator configurator;
private DelegationTokenAuthenticatedURL.Token authToken; private DelegationTokenAuthenticatedURL.Token authToken;
private UserGroupInformation loginUgi;
@Override @Override
public String toString() { public String toString() {
@ -316,6 +319,7 @@ public class KMSClientProvider extends KeyProvider implements CryptoExtension,
KMS_CLIENT_ENC_KEY_CACHE_NUM_REFILL_THREADS_DEFAULT), KMS_CLIENT_ENC_KEY_CACHE_NUM_REFILL_THREADS_DEFAULT),
new EncryptedQueueRefiller()); new EncryptedQueueRefiller());
authToken = new DelegationTokenAuthenticatedURL.Token(); authToken = new DelegationTokenAuthenticatedURL.Token();
loginUgi = UserGroupInformation.getCurrentUser();
} }
private String createServiceURL(URL url) throws IOException { private String createServiceURL(URL url) throws IOException {
@ -374,14 +378,29 @@ public class KMSClientProvider extends KeyProvider implements CryptoExtension,
return conn; return conn;
} }
private HttpURLConnection createConnection(URL url, String method) private HttpURLConnection createConnection(final URL url, String method)
throws IOException { throws IOException {
HttpURLConnection conn; HttpURLConnection conn;
try { try {
DelegationTokenAuthenticatedURL authUrl = // if current UGI is different from UGI at constructor time, behave as
new DelegationTokenAuthenticatedURL(configurator); // proxyuser
conn = authUrl.openConnection(url, authToken); UserGroupInformation currentUgi = UserGroupInformation.getCurrentUser();
} catch (AuthenticationException ex) { final String doAsUser =
(loginUgi.getShortUserName().equals(currentUgi.getShortUserName()))
? null : currentUgi.getShortUserName();
// creating the HTTP connection using the current UGI at constructor time
conn = loginUgi.doAs(new PrivilegedExceptionAction<HttpURLConnection>() {
@Override
public HttpURLConnection run() throws Exception {
DelegationTokenAuthenticatedURL authUrl =
new DelegationTokenAuthenticatedURL(configurator);
return authUrl.openConnection(url, authToken, doAsUser);
}
});
} catch (IOException ex) {
throw ex;
} catch (Exception ex) {
throw new IOException(ex); throw new IOException(ex);
} }
conn.setUseCaches(false); conn.setUseCaches(false);
@ -412,20 +431,27 @@ public class KMSClientProvider extends KeyProvider implements CryptoExtension,
if (status != expected) { if (status != expected) {
InputStream es = null; InputStream es = null;
try { try {
es = conn.getErrorStream();
ObjectMapper mapper = new ObjectMapper();
Map json = mapper.readValue(es, Map.class);
String exClass = (String) json.get(
KMSRESTConstants.ERROR_EXCEPTION_JSON);
String exMsg = (String)
json.get(KMSRESTConstants.ERROR_MESSAGE_JSON);
Exception toThrow; Exception toThrow;
try { String contentType = conn.getHeaderField(CONTENT_TYPE);
ClassLoader cl = KMSClientProvider.class.getClassLoader(); if (contentType != null &&
Class klass = cl.loadClass(exClass); contentType.toLowerCase().startsWith(APPLICATION_JSON_MIME)) {
Constructor constr = klass.getConstructor(String.class); es = conn.getErrorStream();
toThrow = (Exception) constr.newInstance(exMsg); ObjectMapper mapper = new ObjectMapper();
} catch (Exception ex) { Map json = mapper.readValue(es, Map.class);
String exClass = (String) json.get(
KMSRESTConstants.ERROR_EXCEPTION_JSON);
String exMsg = (String)
json.get(KMSRESTConstants.ERROR_MESSAGE_JSON);
try {
ClassLoader cl = KMSClientProvider.class.getClassLoader();
Class klass = cl.loadClass(exClass);
Constructor constr = klass.getConstructor(String.class);
toThrow = (Exception) constr.newInstance(exMsg);
} catch (Exception ex) {
toThrow = new IOException(MessageFormat.format(
"HTTP status [{0}], {1}", status, conn.getResponseMessage()));
}
} else {
toThrow = new IOException(MessageFormat.format( toThrow = new IOException(MessageFormat.format(
"HTTP status [{0}], {1}", status, conn.getResponseMessage())); "HTTP status [{0}], {1}", status, conn.getResponseMessage()));
} }

View File

@ -75,6 +75,17 @@ public class KMSAuthenticationFilter
return props; return props;
} }
protected Configuration getProxyuserConfiguration(FilterConfig filterConfig) {
Map<String, String> proxyuserConf = KMSWebApp.getConfiguration().
getValByRegex("hadoop\\.kms\\.proxyuser\\.");
Configuration conf = new Configuration(false);
for (Map.Entry<String, String> entry : proxyuserConf.entrySet()) {
conf.set(entry.getKey().substring("hadoop.kms.".length()),
entry.getValue());
}
return conf;
}
private static class KMSResponse extends HttpServletResponseWrapper { private static class KMSResponse extends HttpServletResponseWrapper {
public int statusCode; public int statusCode;
public String msg; public String msg;

View File

@ -195,6 +195,46 @@ hadoop-${project.version} $ sbin/kms.sh start
NOTE: You need to restart the KMS for the configuration changes to take NOTE: You need to restart the KMS for the configuration changes to take
effect. effect.
*** KMS Proxyuser Configuration
Each proxyusers must be configured in <<<etc/hadoop/kms-site.xml>>> using the
following properties:
+---+
<property>
<name>hadoop.kms.proxyusers.#USER#.users</name>
<value>*</value>
</property>
<property>
<name>hadoop.kms.proxyusers.#USER#.groups</name>
<value>*</value>
</property>
<property>
<name>hadoop.kms.proxyusers.#USER#.hosts</name>
<value>*</value>
</property>
+---+
<<<#USER#>>> is the username of the proxyuser to configure.
The <<<users>>> property indicates the users that can be impersonated.
The <<<groups>>> property indicates the groups users being impersonated must
belong to.
At least one of the <<<users>>> or <<<groups>>> properties must be defined.
If both are specified, then the configured proxyuser will be able to
impersonate and user in the <<<users>>> list and any user belonging to one of
the groups in the <<<groups>>> list.
The <<<hosts>>> property indicates from which host the proxyuser can make
impersonation requests.
If <<<users>>>, <<<groups>>> or <<<hosts>>> has a <<<*>>>, it means there are
no restrictions for the proxyuser regarding users, groups or hosts.
*** KMS over HTTPS (SSL) *** KMS over HTTPS (SSL)
To configure KMS to work over HTTPS the following 2 properties must be To configure KMS to work over HTTPS the following 2 properties must be

View File

@ -33,6 +33,7 @@ import org.apache.hadoop.security.authorize.AuthorizationException;
import org.apache.hadoop.security.ssl.KeyStoreTestUtil; import org.apache.hadoop.security.ssl.KeyStoreTestUtil;
import org.junit.AfterClass; import org.junit.AfterClass;
import org.junit.Assert; import org.junit.Assert;
import org.junit.Before;
import org.junit.BeforeClass; import org.junit.BeforeClass;
import org.junit.Test; import org.junit.Test;
import org.mortbay.jetty.Connector; import org.mortbay.jetty.Connector;
@ -71,6 +72,13 @@ import java.util.concurrent.Callable;
public class TestKMS { public class TestKMS {
@Before
public void cleanUp() {
// resetting kerberos security
Configuration conf = new Configuration();
UserGroupInformation.setConfiguration(conf);
}
public static File getTestDir() throws Exception { public static File getTestDir() throws Exception {
File file = new File("dummy"); File file = new File("dummy");
file = file.getAbsoluteFile(); file = file.getAbsoluteFile();
@ -261,6 +269,7 @@ public class TestKMS {
principals.add("HTTP/localhost"); principals.add("HTTP/localhost");
principals.add("client"); principals.add("client");
principals.add("client/host"); principals.add("client/host");
principals.add("client1");
for (KMSACLs.Type type : KMSACLs.Type.values()) { for (KMSACLs.Type type : KMSACLs.Type.values()) {
principals.add(type.toString()); principals.add(type.toString());
} }
@ -290,7 +299,9 @@ public class TestKMS {
try { try {
loginContext.login(); loginContext.login();
subject = loginContext.getSubject(); subject = loginContext.getSubject();
return Subject.doAs(subject, action); UserGroupInformation ugi =
UserGroupInformation.getUGIFromSubject(subject);
return ugi.doAs(action);
} finally { } finally {
loginContext.logout(); loginContext.logout();
} }
@ -298,8 +309,13 @@ public class TestKMS {
public void testStartStop(final boolean ssl, final boolean kerberos) public void testStartStop(final boolean ssl, final boolean kerberos)
throws Exception { throws Exception {
Configuration conf = new Configuration();
if (kerberos) {
conf.set("hadoop.security.authentication", "kerberos");
}
UserGroupInformation.setConfiguration(conf);
File testDir = getTestDir(); File testDir = getTestDir();
Configuration conf = createBaseKMSConf(testDir); conf = createBaseKMSConf(testDir);
final String keystore; final String keystore;
final String password; final String password;
@ -327,18 +343,18 @@ public class TestKMS {
runServer(keystore, password, testDir, new KMSCallable() { runServer(keystore, password, testDir, new KMSCallable() {
@Override @Override
public Void call() throws Exception { public Void call() throws Exception {
Configuration conf = new Configuration(); final Configuration conf = new Configuration();
URL url = getKMSUrl(); URL url = getKMSUrl();
Assert.assertEquals(keystore != null, Assert.assertEquals(keystore != null,
url.getProtocol().equals("https")); url.getProtocol().equals("https"));
URI uri = createKMSUri(getKMSUrl()); final URI uri = createKMSUri(getKMSUrl());
final KeyProvider kp = new KMSClientProvider(uri, conf);
if (kerberos) { if (kerberos) {
for (String user : new String[]{"client", "client/host"}) { for (String user : new String[]{"client", "client/host"}) {
doAs(user, new PrivilegedExceptionAction<Void>() { doAs(user, new PrivilegedExceptionAction<Void>() {
@Override @Override
public Void run() throws Exception { public Void run() throws Exception {
final KeyProvider kp = new KMSClientProvider(uri, conf);
// getKeys() empty // getKeys() empty
Assert.assertTrue(kp.getKeys().isEmpty()); Assert.assertTrue(kp.getKeys().isEmpty());
return null; return null;
@ -346,6 +362,7 @@ public class TestKMS {
}); });
} }
} else { } else {
KeyProvider kp = new KMSClientProvider(uri, conf);
// getKeys() empty // getKeys() empty
Assert.assertTrue(kp.getKeys().isEmpty()); Assert.assertTrue(kp.getKeys().isEmpty());
} }
@ -376,8 +393,11 @@ public class TestKMS {
@Test @Test
public void testKMSProvider() throws Exception { public void testKMSProvider() throws Exception {
Configuration conf = new Configuration();
conf.set("hadoop.security.authentication", "kerberos");
UserGroupInformation.setConfiguration(conf);
File confDir = getTestDir(); File confDir = getTestDir();
Configuration conf = createBaseKMSConf(confDir); conf = createBaseKMSConf(confDir);
writeConf(confDir, conf); writeConf(confDir, conf);
runServer(null, null, confDir, new KMSCallable() { runServer(null, null, confDir, new KMSCallable() {
@ -589,8 +609,11 @@ public class TestKMS {
@Test @Test
public void testACLs() throws Exception { public void testACLs() throws Exception {
Configuration conf = new Configuration();
conf.set("hadoop.security.authentication", "kerberos");
UserGroupInformation.setConfiguration(conf);
final File testDir = getTestDir(); final File testDir = getTestDir();
Configuration conf = createBaseKMSConf(testDir); conf = createBaseKMSConf(testDir);
conf.set("hadoop.kms.authentication.type", "kerberos"); conf.set("hadoop.kms.authentication.type", "kerberos");
conf.set("hadoop.kms.authentication.kerberos.keytab", conf.set("hadoop.kms.authentication.kerberos.keytab",
keytab.getAbsolutePath()); keytab.getAbsolutePath());
@ -626,7 +649,7 @@ public class TestKMS {
} catch (AuthorizationException ex) { } catch (AuthorizationException ex) {
//NOP //NOP
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
try { try {
kp.createKey("k", new byte[16], new KeyProvider.Options(conf)); kp.createKey("k", new byte[16], new KeyProvider.Options(conf));
@ -634,7 +657,7 @@ public class TestKMS {
} catch (AuthorizationException ex) { } catch (AuthorizationException ex) {
//NOP //NOP
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
try { try {
kp.rollNewVersion("k"); kp.rollNewVersion("k");
@ -642,7 +665,7 @@ public class TestKMS {
} catch (AuthorizationException ex) { } catch (AuthorizationException ex) {
//NOP //NOP
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
try { try {
kp.rollNewVersion("k", new byte[16]); kp.rollNewVersion("k", new byte[16]);
@ -650,7 +673,7 @@ public class TestKMS {
} catch (AuthorizationException ex) { } catch (AuthorizationException ex) {
//NOP //NOP
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
try { try {
kp.getKeys(); kp.getKeys();
@ -658,7 +681,7 @@ public class TestKMS {
} catch (AuthorizationException ex) { } catch (AuthorizationException ex) {
//NOP //NOP
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
try { try {
kp.getKeysMetadata("k"); kp.getKeysMetadata("k");
@ -666,7 +689,7 @@ public class TestKMS {
} catch (AuthorizationException ex) { } catch (AuthorizationException ex) {
//NOP //NOP
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
try { try {
// we are using JavaKeyStoreProvider for testing, so we know how // we are using JavaKeyStoreProvider for testing, so we know how
@ -676,7 +699,7 @@ public class TestKMS {
} catch (AuthorizationException ex) { } catch (AuthorizationException ex) {
//NOP //NOP
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
try { try {
kp.getCurrentKey("k"); kp.getCurrentKey("k");
@ -684,7 +707,7 @@ public class TestKMS {
} catch (AuthorizationException ex) { } catch (AuthorizationException ex) {
//NOP //NOP
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
try { try {
kp.getMetadata("k"); kp.getMetadata("k");
@ -692,7 +715,7 @@ public class TestKMS {
} catch (AuthorizationException ex) { } catch (AuthorizationException ex) {
//NOP //NOP
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
try { try {
kp.getKeyVersions("k"); kp.getKeyVersions("k");
@ -700,7 +723,7 @@ public class TestKMS {
} catch (AuthorizationException ex) { } catch (AuthorizationException ex) {
//NOP //NOP
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
return null; return null;
@ -716,7 +739,7 @@ public class TestKMS {
new KeyProvider.Options(conf)); new KeyProvider.Options(conf));
Assert.assertNull(kv.getMaterial()); Assert.assertNull(kv.getMaterial());
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
return null; return null;
} }
@ -729,7 +752,7 @@ public class TestKMS {
try { try {
kp.deleteKey("k0"); kp.deleteKey("k0");
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
return null; return null;
} }
@ -744,7 +767,7 @@ public class TestKMS {
new KeyProvider.Options(conf)); new KeyProvider.Options(conf));
Assert.assertNull(kv.getMaterial()); Assert.assertNull(kv.getMaterial());
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
return null; return null;
} }
@ -758,7 +781,7 @@ public class TestKMS {
KeyProvider.KeyVersion kv = kp.rollNewVersion("k1"); KeyProvider.KeyVersion kv = kp.rollNewVersion("k1");
Assert.assertNull(kv.getMaterial()); Assert.assertNull(kv.getMaterial());
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
return null; return null;
} }
@ -773,7 +796,7 @@ public class TestKMS {
kp.rollNewVersion("k1", new byte[16]); kp.rollNewVersion("k1", new byte[16]);
Assert.assertNull(kv.getMaterial()); Assert.assertNull(kv.getMaterial());
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
return null; return null;
} }
@ -823,7 +846,7 @@ public class TestKMS {
createKeyProviderCryptoExtension(kp); createKeyProviderCryptoExtension(kp);
kpCE.decryptEncryptedKey(encKv); kpCE.decryptEncryptedKey(encKv);
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
return null; return null;
} }
@ -836,7 +859,7 @@ public class TestKMS {
try { try {
kp.getKeys(); kp.getKeys();
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
return null; return null;
} }
@ -850,7 +873,7 @@ public class TestKMS {
kp.getMetadata("k1"); kp.getMetadata("k1");
kp.getKeysMetadata("k1"); kp.getKeysMetadata("k1");
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
return null; return null;
} }
@ -879,7 +902,7 @@ public class TestKMS {
} catch (AuthorizationException ex) { } catch (AuthorizationException ex) {
//NOP //NOP
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
return null; return null;
@ -893,8 +916,11 @@ public class TestKMS {
@Test @Test
public void testServicePrincipalACLs() throws Exception { public void testServicePrincipalACLs() throws Exception {
Configuration conf = new Configuration();
conf.set("hadoop.security.authentication", "kerberos");
UserGroupInformation.setConfiguration(conf);
File testDir = getTestDir(); File testDir = getTestDir();
Configuration conf = createBaseKMSConf(testDir); conf = createBaseKMSConf(testDir);
conf.set("hadoop.kms.authentication.type", "kerberos"); conf.set("hadoop.kms.authentication.type", "kerberos");
conf.set("hadoop.kms.authentication.kerberos.keytab", conf.set("hadoop.kms.authentication.kerberos.keytab",
keytab.getAbsolutePath()); keytab.getAbsolutePath());
@ -912,18 +938,19 @@ public class TestKMS {
public Void call() throws Exception { public Void call() throws Exception {
final Configuration conf = new Configuration(); final Configuration conf = new Configuration();
conf.setInt(KeyProvider.DEFAULT_BITLENGTH_NAME, 128); conf.setInt(KeyProvider.DEFAULT_BITLENGTH_NAME, 128);
URI uri = createKMSUri(getKMSUrl()); conf.setInt(KeyProvider.DEFAULT_BITLENGTH_NAME, 64);
final KeyProvider kp = new KMSClientProvider(uri, conf); final URI uri = createKMSUri(getKMSUrl());
doAs("client", new PrivilegedExceptionAction<Void>() { doAs("client", new PrivilegedExceptionAction<Void>() {
@Override @Override
public Void run() throws Exception { public Void run() throws Exception {
try { try {
KeyProvider kp = new KMSClientProvider(uri, conf);
KeyProvider.KeyVersion kv = kp.createKey("ck0", KeyProvider.KeyVersion kv = kp.createKey("ck0",
new KeyProvider.Options(conf)); new KeyProvider.Options(conf));
Assert.assertNull(kv.getMaterial()); Assert.assertNull(kv.getMaterial());
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
return null; return null;
} }
@ -933,11 +960,12 @@ public class TestKMS {
@Override @Override
public Void run() throws Exception { public Void run() throws Exception {
try { try {
KeyProvider kp = new KMSClientProvider(uri, conf);
KeyProvider.KeyVersion kv = kp.createKey("ck1", KeyProvider.KeyVersion kv = kp.createKey("ck1",
new KeyProvider.Options(conf)); new KeyProvider.Options(conf));
Assert.assertNull(kv.getMaterial()); Assert.assertNull(kv.getMaterial());
} catch (Exception ex) { } catch (Exception ex) {
Assert.fail(ex.toString()); Assert.fail(ex.getMessage());
} }
return null; return null;
} }
@ -1014,8 +1042,11 @@ public class TestKMS {
@Test @Test
public void testDelegationTokenAccess() throws Exception { public void testDelegationTokenAccess() throws Exception {
Configuration conf = new Configuration();
conf.set("hadoop.security.authentication", "kerberos");
UserGroupInformation.setConfiguration(conf);
final File testDir = getTestDir(); final File testDir = getTestDir();
Configuration conf = createBaseKMSConf(testDir); conf = createBaseKMSConf(testDir);
conf.set("hadoop.kms.authentication.type", "kerberos"); conf.set("hadoop.kms.authentication.type", "kerberos");
conf.set("hadoop.kms.authentication.kerberos.keytab", conf.set("hadoop.kms.authentication.kerberos.keytab",
keytab.getAbsolutePath()); keytab.getAbsolutePath());
@ -1076,4 +1107,74 @@ public class TestKMS {
}); });
} }
@Test
public void testProxyUser() throws Exception {
Configuration conf = new Configuration();
conf.set("hadoop.security.authentication", "kerberos");
UserGroupInformation.setConfiguration(conf);
final File testDir = getTestDir();
conf = createBaseKMSConf(testDir);
conf.set("hadoop.kms.authentication.type", "kerberos");
conf.set("hadoop.kms.authentication.kerberos.keytab",
keytab.getAbsolutePath());
conf.set("hadoop.kms.authentication.kerberos.principal", "HTTP/localhost");
conf.set("hadoop.kms.authentication.kerberos.name.rules", "DEFAULT");
conf.set("hadoop.kms.proxyuser.client.users", "foo");
conf.set("hadoop.kms.proxyuser.client.hosts", "*");
writeConf(testDir, conf);
runServer(null, null, testDir, new KMSCallable() {
@Override
public Void call() throws Exception {
final Configuration conf = new Configuration();
conf.setInt(KeyProvider.DEFAULT_BITLENGTH_NAME, 64);
final URI uri = createKMSUri(getKMSUrl());
// proxyuser client using kerberos credentials
UserGroupInformation clientUgi = UserGroupInformation.
loginUserFromKeytabAndReturnUGI("client", keytab.getAbsolutePath());
clientUgi.doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
final KeyProvider kp = new KMSClientProvider(uri, conf);
kp.createKey("kAA", new KeyProvider.Options(conf));
// authorized proxyuser
UserGroupInformation fooUgi =
UserGroupInformation.createRemoteUser("foo");
fooUgi.doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
Assert.assertNotNull(kp.createKey("kBB",
new KeyProvider.Options(conf)));
return null;
}
});
// unauthorized proxyuser
UserGroupInformation foo1Ugi =
UserGroupInformation.createRemoteUser("foo1");
foo1Ugi.doAs(new PrivilegedExceptionAction<Void>() {
@Override
public Void run() throws Exception {
try {
kp.createKey("kCC", new KeyProvider.Options(conf));
Assert.fail();
} catch (AuthorizationException ex) {
// OK
} catch (Exception ex) {
Assert.fail(ex.getMessage());
}
return null;
}
});
return null;
}
});
return null;
}
});
}
} }