use of com.emc.storageos.security.geo.TokenResponseBuilder.TokenResponseArtifacts in project coprhd-controller by CoprHD.
the class TokenManagerTests method concurrentTokenKeyBundleMapUpdatesSingleCache.
/**
* Here, we test that in one node of a VDC (one cache), multiple threads
* can add various tokenkeys bundle from 5 other vdcs at the same time
* and the result is a consistent 5 entries in the cache
*
* @throws Exception
*/
@Test
public void concurrentTokenKeyBundleMapUpdatesSingleCache() throws Exception {
// Create 10 distinct bundles (recreating a new TestCoordinator each time
// to simulate 10 vdcs
final HashMap<String, TokenKeysBundle> verifyingMap = new HashMap<String, TokenKeysBundle>();
for (int i = 0; i < 10; i++) {
CoordinatorClient coordinator = new TestCoordinator();
TokenMaxLifeValuesHolder holder = new TokenMaxLifeValuesHolder();
TokenKeyGenerator tokenKeyGenerator1 = new TokenKeyGenerator();
tokenKeyGenerator1.setTokenMaxLifeValuesHolder(holder);
Base64TokenEncoder encoder1 = new Base64TokenEncoder();
encoder1.setCoordinator(coordinator);
encoder1.setTokenKeyGenerator(tokenKeyGenerator1);
encoder1.managerInit();
TokenKeysBundle bundle = tokenKeyGenerator1.readBundle();
verifyingMap.put(String.format("vdc%d", i), bundle);
}
// 1 db, 1 coordinator, 1 cache. Shared across 10 threads
// We are simulating the various services of a node all wanting to
// cache the same stuff at the same time
final DbClient sharedDbClient = getDbClient();
final CoordinatorClient sharedCoordinator = new TestCoordinator();
final InterVDCTokenCacheHelper sharedCacheHelper = new InterVDCTokenCacheHelper();
sharedCacheHelper.setCoordinator(sharedCoordinator);
sharedCacheHelper.setDbClient(sharedDbClient);
TokenMaxLifeValuesHolder holder = new TokenMaxLifeValuesHolder();
sharedCacheHelper.setMaxLifeValuesHolder(holder);
int numThreads = 10;
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
final CountDownLatch waiter = new CountDownLatch(numThreads);
final class InitTester implements Callable {
@Override
public Object call() throws Exception {
// synchronize all threads
waiter.countDown();
waiter.await();
for (int i = 0; i < verifyingMap.size(); i++) {
String vdc = String.format("vdc%d", i);
TokenResponseArtifacts rspArtifacts = new TokenResponseArtifacts(null, null, verifyingMap.get(vdc));
sharedCacheHelper.cacheForeignTokenAndKeys(rspArtifacts, vdc);
}
return null;
}
}
for (int i = 0; i < numThreads; i++) {
executor.submit(new InitTester());
}
executor.shutdown();
Assert.assertTrue(executor.awaitTermination(30, TimeUnit.SECONDS));
if (verifyingMap.size() != sharedCacheHelper.getAllCachedBundles().size()) {
log.error("Mismatched cache and verifying map size: ");
for (Entry<String, TokenKeysBundle> e : sharedCacheHelper.getAllCachedBundles().entrySet()) {
log.error("vdc entry: {}", e.getKey());
}
}
Assert.assertEquals(verifyingMap.size(), sharedCacheHelper.getAllCachedBundles().size());
for (int i = 0; i < verifyingMap.size(); i++) {
String vdc = String.format("vdc%d", i);
TokenKeysBundle fromCache = sharedCacheHelper.getTokenKeysBundle(vdc);
Assert.assertNotNull(fromCache);
Assert.assertTrue(fromCache.getKeyEntries().size() == verifyingMap.get(vdc).getKeyEntries().size() && fromCache.getKeyEntries().get(0).equals(verifyingMap.get(vdc).getKeyEntries().get(0)));
}
}
use of com.emc.storageos.security.geo.TokenResponseBuilder.TokenResponseArtifacts in project coprhd-controller by CoprHD.
the class TokenManagerTests method testCrossVDCTokenValidation.
/**
* testCrossVDCTokenValidation
* Tests that a token from VDC2 and VDC3 can both be validated in VDC1
* given that VDC1's cache has these tokens and keys available.
*
* @throws Exception
*/
@Test
public void testCrossVDCTokenValidation() throws Exception {
commonDefaultSetupForSingleNodeTests();
TokenMaxLifeValuesHolder holder = new TokenMaxLifeValuesHolder();
// VDC1 (validator)
CoordinatorClient coordinatorVDC1 = new TestCoordinator();
InterVDCTokenCacheHelper cacheHelperVDC1 = new InterVDCTokenCacheHelper();
cacheHelperVDC1.setCoordinator(coordinatorVDC1);
cacheHelperVDC1.setDbClient(_dbClient);
cacheHelperVDC1.setMaxLifeValuesHolder(holder);
TokenKeyGenerator tokenKeyGeneratorVDC1 = new TokenKeyGenerator();
tokenKeyGeneratorVDC1.setTokenMaxLifeValuesHolder(holder);
Base64TokenEncoder encoderVDC1 = new Base64TokenEncoder();
encoderVDC1.setCoordinator(coordinatorVDC1);
encoderVDC1.setInterVDCTokenCacheHelper(cacheHelperVDC1);
encoderVDC1.setTokenKeyGenerator(tokenKeyGeneratorVDC1);
encoderVDC1.managerInit();
CassandraTokenManager tokenManagerVDC1 = new CassandraTokenManager();
tokenManagerVDC1.setDbClient(_dbClient);
tokenManagerVDC1.setCoordinator(coordinatorVDC1);
tokenManagerVDC1.setInterVDCTokenCacheHelper(cacheHelperVDC1);
tokenManagerVDC1.setTokenEncoder(encoderVDC1);
tokenManagerVDC1.setTokenMaxLifeValuesHolder(holder);
// VDC2 (creator of token)
CoordinatorClient coordinatorVDC2 = new TestCoordinator();
TokenKeyGenerator tokenKeyGeneratorVDC2 = new TokenKeyGenerator();
tokenKeyGeneratorVDC2.setTokenMaxLifeValuesHolder(holder);
Base64TokenEncoder encoderVDC2 = new Base64TokenEncoder();
encoderVDC2.setCoordinator(coordinatorVDC2);
encoderVDC2.setTokenKeyGenerator(tokenKeyGeneratorVDC2);
encoderVDC2.managerInit();
CassandraTokenManager tokenManagerVDC2 = new CassandraTokenManager();
tokenManagerVDC2.setDbClient(_dbClient);
tokenManagerVDC2.setCoordinator(coordinatorVDC2);
tokenManagerVDC2.setTokenEncoder(encoderVDC2);
tokenManagerVDC2.setTokenMaxLifeValuesHolder(holder);
// VDC3 (creator of token)
CoordinatorClient coordinatorVDC3 = new TestCoordinator();
TokenKeyGenerator tokenKeyGeneratorVDC3 = new TokenKeyGenerator();
tokenKeyGeneratorVDC3.setTokenMaxLifeValuesHolder(holder);
Base64TokenEncoder encoderVDC3 = new Base64TokenEncoder();
encoderVDC3.setCoordinator(coordinatorVDC3);
encoderVDC3.setTokenKeyGenerator(tokenKeyGeneratorVDC3);
encoderVDC3.managerInit();
CassandraTokenManager tokenManagerVDC3 = new CassandraTokenManager();
tokenManagerVDC3.setDbClient(_dbClient);
tokenManagerVDC3.setCoordinator(coordinatorVDC3);
tokenManagerVDC3.setTokenEncoder(encoderVDC3);
tokenManagerVDC3.setTokenMaxLifeValuesHolder(holder);
// VDC2 create a token
// set VdcUtil localvdcid to vdc2 to resulting token is identified as such
VirtualDataCenter localVdc = VdcUtil.getLocalVdc();
localVdc.setShortId("vdc2");
_dbClient.persistObject(localVdc);
VdcUtil.invalidateVdcUrnCache();
StorageOSUserDAO userDAOVDC2 = new StorageOSUserDAO();
userDAOVDC2.setUserName("user1@domain.com");
userDAOVDC2.setIsLocal(false);
String tokenVDC2 = tokenManagerVDC2.getToken(userDAOVDC2);
Assert.assertNotNull(tokenVDC2);
TokenOnWire twVDC2 = encoderVDC2.decode(tokenVDC2);
final Token tokenObjVDC2 = _dbClient.queryObject(Token.class, twVDC2.getTokenId());
Assert.assertNotNull(tokenObjVDC2);
URI userIdVDC2 = tokenObjVDC2.getUserId();
Assert.assertNotNull(userIdVDC2);
final StorageOSUserDAO gotUserVDC2 = tokenManagerVDC2.validateToken(tokenVDC2);
Assert.assertNotNull(gotUserVDC2);
// because we are running this on the same "db" as opposed to 2 different VDCs,
// there will be a conflict when caching the token, since the original is already there
// with the same id. So we are changing the token id and user record id for this
// purpose.
tokenObjVDC2.setId(URIUtil.createId(Token.class));
gotUserVDC2.setId(URIUtil.createId(StorageOSUserDAO.class));
tokenObjVDC2.setUserId(gotUserVDC2.getId());
TokenOnWire tokenToBeCachedVDC2 = TokenOnWire.createTokenOnWire(tokenObjVDC2);
// this re-encoded alternate token is the token that will be cached and validated
// from cache.
final String newEncodedVDC2 = encoderVDC2.encode(tokenToBeCachedVDC2);
// VDC3 create a token
// set VdcUtil localvdcid to vdc3 to resulting token is identified as such
localVdc.setShortId("vdc3");
_dbClient.persistObject(localVdc);
VdcUtil.invalidateVdcUrnCache();
StorageOSUserDAO userDAOVDC3 = new StorageOSUserDAO();
userDAOVDC3.setUserName("user2@domain.com");
userDAOVDC3.setIsLocal(false);
String tokenVDC3 = tokenManagerVDC3.getToken(userDAOVDC3);
Assert.assertNotNull(tokenVDC3);
TokenOnWire twVDC3 = encoderVDC3.decode(tokenVDC3);
final Token tokenObjVDC3 = _dbClient.queryObject(Token.class, twVDC3.getTokenId());
Assert.assertNotNull(tokenObjVDC3);
URI userIdVDC3 = tokenObjVDC3.getUserId();
Assert.assertNotNull(userIdVDC3);
final StorageOSUserDAO gotUserVDC3 = tokenManagerVDC3.validateToken(tokenVDC3);
Assert.assertNotNull(gotUserVDC3);
tokenObjVDC3.setId(URIUtil.createId(Token.class));
gotUserVDC3.setId(URIUtil.createId(StorageOSUserDAO.class));
tokenObjVDC3.setUserId(gotUserVDC3.getId());
TokenOnWire tokenToBeCachedVDC3 = TokenOnWire.createTokenOnWire(tokenObjVDC3);
// this re-encoded alternate token is the token that will be cached and validated
// from cache.
final String newEncodedVDC3 = encoderVDC3.encode(tokenToBeCachedVDC3);
// Cache VDC2 &3's tokens and keys in VDC1.cache
TokenKeysBundle bundleVDC2 = tokenKeyGeneratorVDC2.readBundle();
TokenKeysBundle bundleVDC3 = tokenKeyGeneratorVDC3.readBundle();
TokenResponseArtifacts artifactsVDC2 = new TokenResponseArtifacts(gotUserVDC2, tokenObjVDC2, bundleVDC2);
TokenResponseArtifacts artifactsVDC3 = new TokenResponseArtifacts(gotUserVDC3, tokenObjVDC3, bundleVDC3);
cacheHelperVDC1.cacheForeignTokenAndKeys(artifactsVDC2, "vdc2");
cacheHelperVDC1.cacheForeignTokenAndKeys(artifactsVDC3, "vdc3");
Assert.assertEquals(2, cacheHelperVDC1.getAllCachedBundles().size());
// Validate both tokens using VDC1
// set VdcUtil localvdcid to vdc1 to resulting token is identified as such
localVdc.setShortId("vdc1");
_dbClient.persistObject(localVdc);
VdcUtil.invalidateVdcUrnCache();
StorageOSUserDAO userValidate = tokenManagerVDC1.validateToken(newEncodedVDC2);
Assert.assertNotNull(userValidate);
Assert.assertEquals(userValidate.getUserName(), userDAOVDC2.getUserName());
StorageOSUserDAO userValidate2 = tokenManagerVDC1.validateToken(newEncodedVDC3);
Assert.assertNotNull(userValidate2);
Assert.assertEquals(userValidate2.getUserName(), userDAOVDC3.getUserName());
}
use of com.emc.storageos.security.geo.TokenResponseBuilder.TokenResponseArtifacts in project coprhd-controller by CoprHD.
the class Base64TokenEncoder method getForeignKey.
/**
* Attempts to get a secret key from the provided tokenonwire.
* First attempts from cache, then makes a call to originator vdc if not
* found in cache.
*
* @param tw
* @param encodedToken
* @return
*/
private SecretKey getForeignKey(TokenOnWire tw, String encodedToken) {
String vdcId = URIUtil.parseVdcIdFromURI(tw.getTokenId());
_log.info("Token received from another VDC: {}. Looking in cache for keys", vdcId);
SecretKey foreignKey = interVDCTokenCacheHelper.getForeignSecretKey(vdcId, tw.getEncryptionKeyId());
if (foreignKey == null) {
TokenKeysBundle bundle = interVDCTokenCacheHelper.getTokenKeysBundle(vdcId);
try {
// check if the requested key id falls within reasonable range
if (bundle != null && !interVDCTokenCacheHelper.sanitizeRequestedKeyIds(bundle, tw.getEncryptionKeyId())) {
return null;
}
TokenResponse response = geoClientCacheMgt.getGeoClient(vdcId).getToken(encodedToken, bundle == null ? "0" : bundle.getKeyEntries().get(0), bundle == null ? "0" : bundle.getKeyEntries().size() == 2 ? bundle.getKeyEntries().get(1) : null);
if (response != null) {
TokenResponseArtifacts artifacts = TokenResponseBuilder.parseTokenResponse(response);
interVDCTokenCacheHelper.cacheForeignTokenAndKeys(artifacts, vdcId);
return interVDCTokenCacheHelper.getForeignSecretKey(vdcId, tw.getEncryptionKeyId());
} else {
_log.error("Null response from getForeignToken call. It's possible remote vdc is not reachable.");
}
} catch (Exception e) {
_log.error("Could not validate foreign token ", e);
}
} else {
_log.info("Key found in cache");
}
return foreignKey;
}
use of com.emc.storageos.security.geo.TokenResponseBuilder.TokenResponseArtifacts in project coprhd-controller by CoprHD.
the class CassandraTokenValidator method getForeignToken.
/**
* Queries the remote VDC for token and userdao objects
*
* @param tw TokenOnWire object
* @param rawToken the rawToken to send to the remote vdc
* @return
*/
private StorageOSUserDAO getForeignToken(TokenOnWire tw, String rawToken) {
StorageOSUserDAO userFromCache = this.foreignTokenCacheLookup(tw);
if (userFromCache != null) {
return userFromCache;
}
try {
String shortVDCid = URIUtil.parseVdcIdFromURI(tw.getTokenId());
TokenResponse response = geoClientCacheMgt.getGeoClient(shortVDCid).getToken(rawToken, null, null);
if (response != null) {
TokenResponseArtifacts artifacts = TokenResponseBuilder.parseTokenResponse(response);
_log.info("Got username for foreign token: {}", artifacts.getUser().getUserName());
_log.debug("Got token object: {}", artifacts.getToken().getId().toString());
interVDCTokenCacheHelper.cacheForeignTokenAndKeys(artifacts, shortVDCid);
return artifacts.getUser();
} else {
_log.error("Null response from getForeignToken call. It's possible remote vdc is not reachable.");
}
} catch (Exception e) {
_log.error("Could not validate foreign token ", e);
}
return null;
}
use of com.emc.storageos.security.geo.TokenResponseBuilder.TokenResponseArtifacts in project coprhd-controller by CoprHD.
the class TokenManagerTests method testConcurrentIntraVDCTokenCaching.
/**
* testConcurrentIntraVDCTokenCaching
* Tests that multiple nodes in a single foreign VDC can cache the same token without collision
*
* @throws Exception
*/
@Test
public void testConcurrentIntraVDCTokenCaching() throws Exception {
// common setup and create a token
commonDefaultSetupForSingleNodeTests();
VirtualDataCenter localVdc = VdcUtil.getLocalVdc();
localVdc.setShortId("externalVDCId");
_dbClient.persistObject(localVdc);
VdcUtil.invalidateVdcUrnCache();
StorageOSUserDAO userDAO = new StorageOSUserDAO();
userDAO.setUserName("user1@domain.com");
userDAO.setIsLocal(false);
String token = _tokenManager.getToken(userDAO);
Assert.assertNotNull(token);
TokenOnWire tw1 = _encoder.decode(token);
final Token tokenObj = _dbClient.queryObject(Token.class, tw1.getTokenId());
Assert.assertNotNull(tokenObj);
URI userId = tokenObj.getUserId();
Assert.assertNotNull(userId);
final StorageOSUserDAO gotUser = _tokenManager.validateToken(token);
Assert.assertNotNull(gotUser);
// because we are running this on the same "db" as opposed to 2 different VDCs,
// there will be a conflict when caching the token, since the original is already there
// with the same id. So we are changing the token id and user record id for this
// purpose.
tokenObj.setId(URIUtil.createId(Token.class));
gotUser.setId(URIUtil.createId(StorageOSUserDAO.class));
tokenObj.setUserId(gotUser.getId());
TokenOnWire tokenToBeCached = TokenOnWire.createTokenOnWire(tokenObj);
// this re-encoded alternate token is the token that will be cached and validated
// from cache.
final String newEncoded = _encoder.encode(tokenToBeCached);
final DbClient dbClient = getDbClient();
// note: the same coordinator is being used in all threads. This means that
// token keys will be present in this simulated foreign vdc eventhough we didn't
// explicitly cache them. This should normally fail since we don't have the keys
// but to focus this test on just the token validation from cache, we leave this be.
// A separate test will deal with multiple TestCoordinator() representing different
// zk, in other words true multiple VDCs.
final CoordinatorClient coordinator = new TestCoordinator();
// change it back to vdc1, so that it will not match the vdcid in the token
// created earlier and therefore will be considered a foreign token.
localVdc.setShortId("vdc1");
_dbClient.persistObject(localVdc);
VdcUtil.invalidateVdcUrnCache();
int numThreads = 5;
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
final CountDownLatch waiter = new CountDownLatch(numThreads);
final class InitTester implements Callable {
@Override
public Object call() throws Exception {
// create node artifacts
TokenMaxLifeValuesHolder holder = new TokenMaxLifeValuesHolder();
holder.setForeignTokenCacheExpirationInMins(1);
InterVDCTokenCacheHelper cacheHelper = new InterVDCTokenCacheHelper();
cacheHelper.setCoordinator(coordinator);
cacheHelper.setDbClient(dbClient);
cacheHelper.setMaxLifeValuesHolder(holder);
TokenKeyGenerator tokenKeyGenerator1 = new TokenKeyGenerator();
tokenKeyGenerator1.setTokenMaxLifeValuesHolder(holder);
Base64TokenEncoder encoder1 = new Base64TokenEncoder();
encoder1.setCoordinator(coordinator);
encoder1.setInterVDCTokenCacheHelper(cacheHelper);
encoder1.setTokenKeyGenerator(tokenKeyGenerator1);
encoder1.managerInit();
CassandraTokenManager tokenManager1 = new CassandraTokenManager();
tokenManager1.setDbClient(dbClient);
tokenManager1.setCoordinator(coordinator);
tokenManager1.setTokenMaxLifeValuesHolder(holder);
tokenManager1.setInterVDCTokenCacheHelper(cacheHelper);
tokenManager1.setTokenEncoder(encoder1);
TokenResponseArtifacts artifacts = new TokenResponseArtifacts(gotUser, tokenObj, null);
// synchronize all threads
waiter.countDown();
waiter.await();
// Cache the token artifacts. Each thread will try at the same time
// End result is, the token/user values will all be the same anyway
// but the important is there is no concurrency issue between the first
// thread that will try to add to the cache, and the others that will simply
// update it.
cacheHelper.cacheForeignTokenAndKeys(artifacts, null);
// First validation should work. It validates from the cache.
StorageOSUserDAO userFromDB = tokenManager1.validateToken(newEncoded);
Assert.assertNotNull(userFromDB);
Assert.assertEquals(userFromDB.getUserName(), gotUser.getUserName());
// wait longer than cache expiration (longer than 1 minute in our case)
// token's cache expiration should be expired
Thread.sleep((holder.getForeignTokenCacheExpirationInMins() + 1) * 60000);
userFromDB = tokenManager1.validateToken(newEncoded);
Assert.assertNull(userFromDB);
return null;
}
}
for (int i = 0; i < numThreads; i++) {
executor.submit(new InitTester());
}
executor.shutdown();
Assert.assertTrue(executor.awaitTermination(180, TimeUnit.SECONDS));
}
Aggregations