HDFS-7597. DelegationTokenIdentifier should cache the TokenIdentifier to UGI mapping. Contributed by Daryn Sharp, Bob Hansen, and Xiao Chen.
(cherry picked from commit d433b16ce6
)
This commit is contained in:
parent
e0f4397232
commit
ad50a64ded
|
@ -21,13 +21,20 @@ package org.apache.hadoop.hdfs.security.token.delegation;
|
||||||
import java.io.ByteArrayInputStream;
|
import java.io.ByteArrayInputStream;
|
||||||
import java.io.DataInputStream;
|
import java.io.DataInputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import org.apache.commons.collections.map.LRUMap;
|
||||||
import org.apache.hadoop.classification.InterfaceAudience;
|
import org.apache.hadoop.classification.InterfaceAudience;
|
||||||
import org.apache.hadoop.hdfs.web.WebHdfsConstants;
|
import org.apache.hadoop.hdfs.web.WebHdfsConstants;
|
||||||
import org.apache.hadoop.io.Text;
|
import org.apache.hadoop.io.Text;
|
||||||
|
import org.apache.hadoop.security.UserGroupInformation;
|
||||||
import org.apache.hadoop.security.token.Token;
|
import org.apache.hadoop.security.token.Token;
|
||||||
|
import org.apache.hadoop.security.token.TokenIdentifier;
|
||||||
import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenIdentifier;
|
import org.apache.hadoop.security.token.delegation.AbstractDelegationTokenIdentifier;
|
||||||
|
|
||||||
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A delegation token identifier that is specific to HDFS.
|
* A delegation token identifier that is specific to HDFS.
|
||||||
*/
|
*/
|
||||||
|
@ -37,6 +44,15 @@ public class DelegationTokenIdentifier
|
||||||
public static final Text HDFS_DELEGATION_KIND =
|
public static final Text HDFS_DELEGATION_KIND =
|
||||||
new Text("HDFS_DELEGATION_TOKEN");
|
new Text("HDFS_DELEGATION_TOKEN");
|
||||||
|
|
||||||
|
@SuppressWarnings("unchecked")
|
||||||
|
private static Map<TokenIdentifier, UserGroupInformation> ugiCache =
|
||||||
|
Collections.synchronizedMap(new LRUMap(64));
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
public void clearCache() {
|
||||||
|
ugiCache.clear();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create an empty delegation token identifier for reading into.
|
* Create an empty delegation token identifier for reading into.
|
||||||
*/
|
*/
|
||||||
|
@ -58,6 +74,16 @@ public class DelegationTokenIdentifier
|
||||||
return HDFS_DELEGATION_KIND;
|
return HDFS_DELEGATION_KIND;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public UserGroupInformation getUser() {
|
||||||
|
UserGroupInformation ugi = ugiCache.get(this);
|
||||||
|
if (ugi == null) {
|
||||||
|
ugi = super.getUser();
|
||||||
|
ugiCache.put(this, ugi);
|
||||||
|
}
|
||||||
|
return ugi;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
return getKind() + " token " + getSequenceNumber()
|
return getKind() + " token " + getSequenceNumber()
|
||||||
|
|
|
@ -61,6 +61,13 @@ public class DataNodeUGIProvider {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@VisibleForTesting
|
||||||
|
void clearCache() throws IOException {
|
||||||
|
if (UserGroupInformation.isSecurityEnabled()) {
|
||||||
|
params.delegationToken().decodeIdentifier().clearCache();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
UserGroupInformation ugi() throws IOException {
|
UserGroupInformation ugi() throws IOException {
|
||||||
UserGroupInformation ugi;
|
UserGroupInformation ugi;
|
||||||
|
|
||||||
|
|
|
@ -242,7 +242,36 @@ public class TestDelegationToken {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDelegationTokenUgi() throws Exception {
|
||||||
|
final DistributedFileSystem dfs = cluster.getFileSystem();
|
||||||
|
Token<?>[] tokens = dfs.addDelegationTokens("renewer", null);
|
||||||
|
Assert.assertEquals(1, tokens.length);
|
||||||
|
Token<?> token1 = tokens[0];
|
||||||
|
DelegationTokenIdentifier ident =
|
||||||
|
(DelegationTokenIdentifier) token1.decodeIdentifier();
|
||||||
|
UserGroupInformation expectedUgi = ident.getUser();
|
||||||
|
|
||||||
|
// get 2 new instances (clones) of the identifier, query their ugi
|
||||||
|
// twice each, all ugi instances should be equivalent
|
||||||
|
for (int i=0; i<2; i++) {
|
||||||
|
DelegationTokenIdentifier identClone =
|
||||||
|
(DelegationTokenIdentifier)token1.decodeIdentifier();
|
||||||
|
Assert.assertEquals(ident, identClone);
|
||||||
|
Assert.assertNotSame(ident, identClone);
|
||||||
|
Assert.assertSame(expectedUgi, identClone.getUser());
|
||||||
|
Assert.assertSame(expectedUgi, identClone.getUser());
|
||||||
|
}
|
||||||
|
|
||||||
|
// a new token must decode to a different ugi instance than the first token
|
||||||
|
tokens = dfs.addDelegationTokens("renewer", null);
|
||||||
|
Assert.assertEquals(1, tokens.length);
|
||||||
|
Token<?> token2 = tokens[0];
|
||||||
|
Assert.assertNotEquals(token1, token2);
|
||||||
|
Assert.assertNotSame(expectedUgi, token2.decodeIdentifier().getUser());
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Test that the delegation token secret manager only runs when the
|
* Test that the delegation token secret manager only runs when the
|
||||||
* NN is out of safe mode. This is because the secret manager
|
* NN is out of safe mode. This is because the secret manager
|
||||||
|
|
|
@ -109,6 +109,7 @@ public class TestJspHelper {
|
||||||
|
|
||||||
//Test attribute name.node.address
|
//Test attribute name.node.address
|
||||||
//Set the nnaddr url parameter to null.
|
//Set the nnaddr url parameter to null.
|
||||||
|
token.decodeIdentifier().clearCache();
|
||||||
when(request.getParameter(JspHelper.NAMENODE_ADDRESS)).thenReturn(null);
|
when(request.getParameter(JspHelper.NAMENODE_ADDRESS)).thenReturn(null);
|
||||||
InetSocketAddress addr = new InetSocketAddress("localhost", 2222);
|
InetSocketAddress addr = new InetSocketAddress("localhost", 2222);
|
||||||
when(context.getAttribute(NameNodeHttpServer.NAMENODE_ADDRESS_ATTRIBUTE_KEY))
|
when(context.getAttribute(NameNodeHttpServer.NAMENODE_ADDRESS_ATTRIBUTE_KEY))
|
||||||
|
@ -116,7 +117,12 @@ public class TestJspHelper {
|
||||||
verifyServiceInToken(context, request, addr.getAddress().getHostAddress()
|
verifyServiceInToken(context, request, addr.getAddress().getHostAddress()
|
||||||
+ ":2222");
|
+ ":2222");
|
||||||
|
|
||||||
//Test service already set in the token
|
//Test service already set in the token and DN doesn't change service
|
||||||
|
//when it doesn't know the NN service addr
|
||||||
|
userText = new Text(user+"2");
|
||||||
|
dtId = new DelegationTokenIdentifier(userText, userText, null);
|
||||||
|
token = new Token<DelegationTokenIdentifier>(
|
||||||
|
dtId, new DummySecretManager(0, 0, 0, 0));
|
||||||
token.setService(new Text("3.3.3.3:3333"));
|
token.setService(new Text("3.3.3.3:3333"));
|
||||||
tokenString = token.encodeToUrlString();
|
tokenString = token.encodeToUrlString();
|
||||||
//Set the name.node.address attribute in Servlet context to null
|
//Set the name.node.address attribute in Servlet context to null
|
||||||
|
|
|
@ -121,6 +121,7 @@ public class TestDataNodeUGIProvider {
|
||||||
"With UGI cache, two UGIs for the different token should not be same",
|
"With UGI cache, two UGIs for the different token should not be same",
|
||||||
ugi11, url22);
|
ugi11, url22);
|
||||||
|
|
||||||
|
ugiProvider2.clearCache();
|
||||||
awaitCacheEmptyDueToExpiration();
|
awaitCacheEmptyDueToExpiration();
|
||||||
ugi12 = ugiProvider1.ugi();
|
ugi12 = ugiProvider1.ugi();
|
||||||
url22 = ugiProvider2.ugi();
|
url22 = ugiProvider2.ugi();
|
||||||
|
|
Loading…
Reference in New Issue