HDFS-14305. Fix serial number calculation in BlockTokenSecretManager to avoid token key ID overlap between NameNodes. Contributed by He Xiaoqiao.

This commit is contained in:
Erik Krogen 2019-02-28 08:48:10 -08:00 committed by Erik Krogen
parent d045f02a8d
commit af16db86d4
2 changed files with 45 additions and 7 deletions

View File

@ -63,6 +63,17 @@ public class BlockTokenSecretManager extends
public static final Token<BlockTokenIdentifier> DUMMY_TOKEN = new Token<BlockTokenIdentifier>(); public static final Token<BlockTokenIdentifier> DUMMY_TOKEN = new Token<BlockTokenIdentifier>();
/**
* In order to prevent serial No. of different NameNode from overlapping,
* Using 6 bits (identify 64=2^6 namenodes, and presuppose that no scenario
* where deploy more than 64 namenodes (include ANN, SBN, Observers, etc.)
* in one namespace) to identify index of NameNode, and the remainder 26 bits
* auto-incr to change the serial No.
*/
@VisibleForTesting
public static final int NUM_VALID_BITS = 26;
private static final int LOW_MASK = (1 << NUM_VALID_BITS) - 1;
private final boolean isMaster; private final boolean isMaster;
/** /**
@ -79,8 +90,8 @@ public class BlockTokenSecretManager extends
private String blockPoolId; private String blockPoolId;
private final String encryptionAlgorithm; private final String encryptionAlgorithm;
private final int intRange; private final int nnIndex;
private final int nnRangeStart;
private final boolean useProto; private final boolean useProto;
private final SecureRandom nonceGenerator = new SecureRandom(); private final SecureRandom nonceGenerator = new SecureRandom();
@ -129,8 +140,7 @@ public class BlockTokenSecretManager extends
private BlockTokenSecretManager(boolean isMaster, long keyUpdateInterval, private BlockTokenSecretManager(boolean isMaster, long keyUpdateInterval,
long tokenLifetime, String blockPoolId, String encryptionAlgorithm, long tokenLifetime, String blockPoolId, String encryptionAlgorithm,
int nnIndex, int numNNs, boolean useProto) { int nnIndex, int numNNs, boolean useProto) {
this.intRange = Integer.MAX_VALUE / numNNs; this.nnIndex = nnIndex;
this.nnRangeStart = intRange * nnIndex;
this.isMaster = isMaster; this.isMaster = isMaster;
this.keyUpdateInterval = keyUpdateInterval; this.keyUpdateInterval = keyUpdateInterval;
this.tokenLifetime = tokenLifetime; this.tokenLifetime = tokenLifetime;
@ -144,8 +154,7 @@ public class BlockTokenSecretManager extends
@VisibleForTesting @VisibleForTesting
public synchronized void setSerialNo(int serialNo) { public synchronized void setSerialNo(int serialNo) {
// we mod the serial number by the range and then add that times the index this.serialNo = (serialNo & LOW_MASK) | (nnIndex << NUM_VALID_BITS);
this.serialNo = (serialNo % intRange) + (nnRangeStart);
} }
public void setBlockPoolId(String blockPoolId) { public void setBlockPoolId(String blockPoolId) {

View File

@ -116,7 +116,36 @@ public class TestFailoverWithBlockTokensEnabled {
} }
} }
} }
@Test
public void testSerialNumberMaskMatchIndex() {
BlockTokenSecretManager btsm1 = cluster.getNamesystem(0).getBlockManager()
.getBlockTokenSecretManager();
BlockTokenSecretManager btsm2 = cluster.getNamesystem(1).getBlockManager()
.getBlockTokenSecretManager();
BlockTokenSecretManager btsm3 = cluster.getNamesystem(2).getBlockManager()
.getBlockTokenSecretManager();
int[] testSet = {0, Integer.MAX_VALUE, Integer.MIN_VALUE,
Integer.MAX_VALUE / 2, Integer.MIN_VALUE / 2,
Integer.MAX_VALUE / 3, Integer.MIN_VALUE / 3};
for (int i = 0; i < testSet.length; i++) {
setAndCheckHighBitsSerialNumber(testSet[i], btsm1, 0);
setAndCheckHighBitsSerialNumber(testSet[i], btsm2, 1);
setAndCheckHighBitsSerialNumber(testSet[i], btsm3, 2);
}
}
/**
* Check mask of serial number if equal to index of NameNode.
*/
private void setAndCheckHighBitsSerialNumber(int serialNumber,
BlockTokenSecretManager btsm, int nnIndex) {
btsm.setSerialNo(serialNumber);
int serialNo = btsm.getSerialNoForTesting();
int index = serialNo >> BlockTokenSecretManager.NUM_VALID_BITS;
assertEquals(index, nnIndex);
}
@Test @Test
public void ensureInvalidBlockTokensAreRejected() throws IOException, public void ensureInvalidBlockTokensAreRejected() throws IOException,
URISyntaxException { URISyntaxException {