use of com.emc.storageos.security.authentication.TokenOnWire in project coprhd-controller by CoprHD.
the class TokenManagerTests method testTokens.
/**
* main set of tests for tokens
*/
@Test
public void testTokens() throws Exception {
commonDefaultSetupForSingleNodeTests();
// Test - new ticket issue
StorageOSUserDAO userDAO = new StorageOSUserDAO();
userDAO.setUserName("user1");
userDAO.setIsLocal(true);
long now = System.currentTimeMillis() / (60 * 1000);
final String token = _tokenManager.getToken(userDAO);
Assert.assertNotNull(token);
TokenOnWire tw1 = _encoder.decode(token);
Token tokenObj = _dbClient.queryObject(Token.class, tw1.getTokenId());
Assert.assertNotNull(tokenObj);
Assert.assertNotNull(tokenObj.getUserId());
Assert.assertTrue(tokenObj.getExpirationTime() >= (now + 4));
final URI userId = tokenObj.getUserId();
// verify token
StorageOSUserDAO gotUser = _tokenManager.validateToken(token);
Assert.assertNotNull(gotUser);
Assert.assertEquals(userId, gotUser.getId());
// Test - update user info, reuse token
StringSet groups = new StringSet();
groups.add("gr1");
groups.add("gr2");
userDAO.setGroups(groups);
StringSet attributes = new StringSet();
attributes.add("atrr1");
attributes.add("attr2");
userDAO.setAttributes(attributes);
String token2 = _tokenManager.getToken(userDAO);
// different tokens for same user record
Assert.assertFalse(token.equals(token2));
TokenOnWire tw2 = _encoder.decode(token2);
Assert.assertFalse(tw1.getTokenId().equals(tw2.getTokenId()));
tokenObj = _dbClient.queryObject(Token.class, tw2.getTokenId());
Assert.assertNotNull(tokenObj);
Assert.assertNotNull(tokenObj.getUserId());
Assert.assertEquals(userId, tokenObj.getUserId());
StorageOSUserDAO userInfo = _dbClient.queryObject(StorageOSUserDAO.class, userId);
Assert.assertNotNull(userInfo);
Assert.assertEquals(userId, userInfo.getId());
Assert.assertFalse(userInfo.getInactive());
Assert.assertEquals(groups.size(), userInfo.getGroups().size());
Assert.assertEquals(attributes.size(), userInfo.getAttributes().size());
Assert.assertTrue(userInfo.getIsLocal());
// verify token
gotUser = _tokenManager.validateToken(token2);
Assert.assertNotNull(gotUser);
Assert.assertEquals(userId, gotUser.getId());
// Test - update user info, new token
userDAO = new StorageOSUserDAO();
userDAO.setUserName("user1");
groups = new StringSet();
groups.add("gr1");
userDAO.setGroups(groups);
attributes = new StringSet();
attributes.add("atrr1");
attributes.add("attr2");
attributes.add("attr3");
userDAO.setAttributes(attributes);
// new token
final String token3 = _tokenManager.getToken(userDAO);
Assert.assertFalse(token2.equals(token3));
TokenOnWire tw3 = _encoder.decode(token3);
tokenObj = _dbClient.queryObject(Token.class, tw3.getTokenId());
Assert.assertNotNull(tokenObj);
Assert.assertNotNull(tokenObj.getUserId());
Assert.assertEquals(userId, tokenObj.getUserId());
userInfo = _dbClient.queryObject(StorageOSUserDAO.class, userId);
Assert.assertNotNull(userInfo);
Assert.assertEquals(userId, userInfo.getId());
Assert.assertFalse(userInfo.getInactive());
Assert.assertEquals(groups.size(), userInfo.getGroups().size());
Assert.assertEquals(attributes.size(), userInfo.getAttributes().size());
Assert.assertTrue(userInfo.getIsLocal());
// verify token
gotUser = _tokenManager.validateToken(token3);
Assert.assertNotNull(gotUser);
Assert.assertEquals(userId, gotUser.getId());
// Test - idle time timeout
tokenObj = _dbClient.queryObject(Token.class, tw1.getTokenId());
// extend expiration by 10min, so that will not happen
now = (System.currentTimeMillis() / (60 * 1000));
tokenObj.setLastAccessTime(now);
tokenObj.setExpirationTime(now + 5);
_dbClient.persistObject(tokenObj);
int count = 8;
while (count-- > 0) {
// validate every 30 sec, for the next 4 min
Thread.sleep(30 * 1000);
gotUser = _tokenManager.validateToken(token);
Assert.assertNotNull(gotUser);
}
// set last access time back
tokenObj = _dbClient.queryObject(Token.class, tw1.getTokenId());
tokenObj.setLastAccessTime((System.currentTimeMillis() / (60 * 1000)) - 3);
_dbClient.persistObject(tokenObj);
// validate token on the old token - should fail
gotUser = _tokenManager.validateToken(token);
Assert.assertNull(gotUser);
// token object should be deleted from db,
// but user info should not be effected because we have another token pointing to it
tokenObj = _dbClient.queryObject(Token.class, tw1.getTokenId());
Assert.assertNull(tokenObj);
userInfo = _dbClient.queryObject(StorageOSUserDAO.class, userId);
Assert.assertNotNull(userInfo);
Assert.assertFalse(userInfo.getInactive());
// Test - deletion of token
// should set userinfo inactive - because this is the last token pointing to it
_tokenManager.deleteToken(token2);
_tokenManager.deleteToken(token3);
userInfo = _dbClient.queryObject(StorageOSUserDAO.class, userId);
Assert.assertNotNull(userInfo);
Assert.assertTrue(userInfo.getInactive());
// Test - with inactive user info - new token request
// new token and new user info created - with possible race condition to create more than one each
int numThreads = 5;
final List<String> tokens = Collections.synchronizedList(new ArrayList<String>());
final List<URI> userIds = Collections.synchronizedList(new ArrayList<URI>());
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
final CountDownLatch wait = new CountDownLatch(numThreads);
for (int index = 0; index < numThreads; index++) {
executor.submit(new Callable<Object>() {
@Override
public Object call() throws Exception {
wait.countDown();
wait.await();
StorageOSUserDAO userDAO = new StorageOSUserDAO();
userDAO.setUserName("user1");
String token4 = _tokenManager.getToken(userDAO);
TokenOnWire tw4 = _encoder.decode(token4);
Assert.assertFalse(token3.equals(token4));
Assert.assertFalse(token.equals(token4));
Token tokenObj = _dbClient.queryObject(Token.class, tw4.getTokenId());
Assert.assertNotNull(tokenObj);
Assert.assertNotNull(tokenObj.getUserId());
Assert.assertFalse(userId.equals(tokenObj.getUserId()));
StorageOSUserDAO userInfo = _dbClient.queryObject(StorageOSUserDAO.class, tokenObj.getUserId());
Assert.assertNotNull(userInfo);
Assert.assertEquals(userDAO.getUserName(), userInfo.getUserName());
Assert.assertFalse(userInfo.getInactive());
Assert.assertFalse(userInfo.getIsLocal());
tokens.add(token4);
userIds.add(userInfo.getId());
return null;
}
});
}
executor.shutdown();
Assert.assertTrue(executor.awaitTermination(60, TimeUnit.SECONDS));
Assert.assertTrue(!tokens.isEmpty());
Assert.assertTrue(!userIds.isEmpty());
// Test - delete all tokens
_tokenManager.deleteAllTokensForUser(userDAO.getUserName(), true);
List<URI> tokensURIs = new ArrayList<URI>();
for (String rawToken : tokens) {
tokensURIs.add(_encoder.decode(rawToken).getTokenId());
}
List<Token> allTokens = _dbClient.queryObject(Token.class, tokensURIs);
Assert.assertTrue(allTokens.isEmpty());
List<StorageOSUserDAO> users = _dbClient.queryObject(StorageOSUserDAO.class, userIds);
for (StorageOSUserDAO user : users) {
Assert.assertTrue(user.getInactive());
URIQueryResultList tokensForUser = new URIQueryResultList();
_dbClient.queryByConstraint(ContainmentConstraint.Factory.getUserIdTokenConstraint(userId), tokensForUser);
Assert.assertFalse(tokensForUser.iterator().hasNext());
}
// Test - expired token deleting
userDAO = new StorageOSUserDAO();
userDAO.setUserName("user1");
String dt1 = _tokenManager.getToken(userDAO);
TokenOnWire twdt1 = _encoder.decode(dt1);
tokenObj = _dbClient.queryObject(Token.class, twdt1.getTokenId());
Assert.assertNotNull(tokenObj);
Assert.assertNotNull(tokenObj.getUserId());
URI du1 = tokenObj.getUserId();
userDAO = new StorageOSUserDAO();
userDAO.setUserName("user2");
String dt2 = _tokenManager.getToken(userDAO);
TokenOnWire twdt2 = _encoder.decode(dt2);
tokenObj = _dbClient.queryObject(Token.class, twdt2.getTokenId());
Assert.assertNotNull(tokenObj);
Assert.assertNotNull(tokenObj.getUserId());
URI du2 = tokenObj.getUserId();
Thread.sleep(3 * 60 * 1000);
_tokenManager.runCleanupNow();
tokenObj = _dbClient.queryObject(Token.class, twdt1.getTokenId());
Assert.assertNull(tokenObj);
tokenObj = _dbClient.queryObject(Token.class, twdt2.getTokenId());
Assert.assertNull(tokenObj);
userDAO = _dbClient.queryObject(StorageOSUserDAO.class, du1);
Assert.assertTrue(userDAO.getInactive());
userDAO = _dbClient.queryObject(StorageOSUserDAO.class, du2);
Assert.assertTrue(userDAO.getInactive());
// test limits
userDAO = new StorageOSUserDAO();
userDAO.setUserName("user1");
for (int i = 0; i < 100; i++) {
dt1 = _tokenManager.getToken(userDAO);
twdt1 = _encoder.decode(dt1);
tokenObj = _dbClient.queryObject(Token.class, twdt1.getTokenId());
Assert.assertNotNull(tokenObj);
Assert.assertNotNull(tokenObj.getUserId());
}
// next get, will throw limit exception
try {
dt1 = _tokenManager.getToken(userDAO);
Assert.fail("The token limit is exceeded. The token for user1 should not be generated.");
} catch (UnauthorizedException ex) {
// this exception is an expected one.
Assert.assertTrue(true);
}
}
use of com.emc.storageos.security.authentication.TokenOnWire in project coprhd-controller by CoprHD.
the class TokenManagerTests method testRequestedTokenMapCleanup.
/**
* This test checks that when the TokenManager's cleanup thread is called,
* it deletes not only expired tokens but also their related RequestedTokenMap
* entry if it exists (and doesn't crash if there isn't one).
*/
@Test
public void testRequestedTokenMapCleanup() throws Exception {
commonDefaultSetupForSingleNodeTests();
// create a token
StorageOSUserDAO userDAO = new StorageOSUserDAO();
userDAO.setUserName("user1");
userDAO.setIsLocal(true);
final String token = _tokenManager.getToken(userDAO);
Assert.assertNotNull(token);
TokenOnWire tw1 = _encoder.decode(token);
Token tokenObj = _dbClient.queryObject(Token.class, tw1.getTokenId());
Assert.assertNotNull(tokenObj);
// add a requested map for this token
RequestedTokenMap map = new RequestedTokenMap();
map.setId(URIUtil.createId(RequestedTokenMap.class));
map.setTokenID(tokenObj.getId().toString());
map.addVDCID("vdc1");
_dbClient.persistObject(map);
// create a second token, no requested map entry this time.
final String token2 = _tokenManager.getToken(userDAO);
Assert.assertNotNull(token2);
TokenOnWire tw2 = _encoder.decode(token2);
Token tokenObj2 = _dbClient.queryObject(Token.class, tw2.getTokenId());
Assert.assertNotNull(tokenObj2);
Thread.sleep(3 * 60 * 1000);
_tokenManager.runCleanupNow();
Assert.assertNull(_dbClient.queryObject(Token.class, tw1.getTokenId()));
Assert.assertNull(_requestedTokenMapHelper.getTokenMap(tw1.getTokenId().toString()));
Assert.assertNull(_dbClient.queryObject(RequestedTokenMap.class, map.getId()));
Assert.assertNull(_dbClient.queryObject(Token.class, tw2.getTokenId()));
Assert.assertNull(_requestedTokenMapHelper.getTokenMap(tw2.getTokenId().toString()));
}
use of com.emc.storageos.security.authentication.TokenOnWire in project coprhd-controller by CoprHD.
the class TokenManagerTests method testConcurrentRotations.
/**
* Have 15 threads attempt a rotation. 14 should realize that rotation have already happen
* and not do anything. At the end, the current key id should be uniform across all 15 threads.
* Additionally, the previous key id should still be valid.
*/
@Test
public void testConcurrentRotations() throws Exception {
// For this test, we need our custom setup, with several
// tokenManagers sharing a common TestCoordinator. This will
// simulate shared zookeeper data on the cluster. And the different
// tokenManagers/KeyGenerators will simulate the different nodes.
DbClient dbClient = getDbClient();
CoordinatorClient coordinator = new TestCoordinator();
final int ROTATION_INTERVAL_MSECS = 5000;
int numThreads = 15;
ExecutorService executor = Executors.newFixedThreadPool(numThreads);
final CountDownLatch waiter = new CountDownLatch(numThreads);
final class InitTester implements Callable {
CoordinatorClient _coordinator = null;
DbClient _client = null;
KeyIdsHolder _holder = null;
public InitTester(CoordinatorClient coord, DbClient client, KeyIdsHolder holder) {
_coordinator = coord;
_client = client;
_holder = holder;
}
@Override
public Object call() throws Exception {
// create node artifacts
CassandraTokenManager tokenManager1 = new CassandraTokenManager();
Base64TokenEncoder encoder1 = new Base64TokenEncoder();
TokenKeyGenerator tokenKeyGenerator1 = new TokenKeyGenerator();
tokenManager1.setDbClient(_client);
tokenManager1.setCoordinator(_coordinator);
encoder1.setCoordinator(_coordinator);
tokenManager1.setTokenEncoder(encoder1);
TokenMaxLifeValuesHolder holder = new TokenMaxLifeValuesHolder();
tokenManager1.setTokenMaxLifeValuesHolder(holder);
tokenKeyGenerator1.setTokenMaxLifeValuesHolder(holder);
encoder1.setTokenKeyGenerator(tokenKeyGenerator1);
holder.setKeyRotationIntervalInMSecs(ROTATION_INTERVAL_MSECS);
encoder1.managerInit();
// synchronize all threads
waiter.countDown();
waiter.await();
// everybody gets a token using the key before the rotation
StorageOSUserDAO userDAO = new StorageOSUserDAO();
userDAO.setUserName("user1");
final String token = tokenManager1.getToken(userDAO);
Assert.assertNotNull(token);
TokenOnWire tw = encoder1.decode(token);
String previousKey = tw.getEncryptionKeyId();
// cause the rotation
Thread.sleep((ROTATION_INTERVAL_MSECS + 1000));
final String token2 = tokenManager1.getToken(userDAO);
Assert.assertNotNull(token2);
TokenOnWire tw2 = encoder1.decode(token2);
// save the new key in the set to check later that all threads agree
// this is the new key
_holder.addToSet(tw2.getEncryptionKeyId());
// validate token created with the previous key to make sure
// rotation didn't mess up the previous key
StorageOSUserDAO gotUser = tokenManager1.validateToken(token);
Assert.assertNotNull(gotUser);
return null;
}
}
KeyIdsHolder holder = new KeyIdsHolder();
for (int i = 0; i < numThreads; i++) {
executor.submit(new InitTester(coordinator, dbClient, holder));
}
executor.shutdown();
Assert.assertTrue(executor.awaitTermination(60, TimeUnit.SECONDS));
// after all is said and done, all tokens created in all 15 threads, should have been
// created with the same key id.
Assert.assertEquals(1, holder.getSetSize());
}
use of com.emc.storageos.security.authentication.TokenOnWire 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));
}
use of com.emc.storageos.security.authentication.TokenOnWire in project coprhd-controller by CoprHD.
the class TokenManagerTests method testTokenKeysSignature.
/**
* tests for token signature manipulation
*
* @throws Exception
*/
@Test
public void testTokenKeysSignature() throws Exception {
commonDefaultSetupForSingleNodeTests();
StorageOSUserDAO userDAO = new StorageOSUserDAO();
userDAO.setUserName("user1");
userDAO.setIsLocal(true);
final String token = _tokenManager.getToken(userDAO);
Assert.assertNotNull(token);
TokenOnWire tw1 = _encoder.decode(token);
// verify token
StorageOSUserDAO gotUser = _tokenManager.validateToken(token);
Assert.assertNotNull(gotUser);
// base64 decode the token, just to look at the version field and
// make sure it is set to what we think.
byte[] decoded = Base64.decodeBase64(token.getBytes("UTF-8"));
SignedToken stOffTheWire = (SignedToken) _serializer.fromByteArray(SignedToken.class, decoded);
Assert.assertEquals(stOffTheWire.getTokenEncodingVersion(), Base64TokenEncoder.VIPR_ENCODING_VERSION);
// Re-encode the valid token, using a bad signature. Try to validate that.
byte[] reserialized = _serializer.toByteArray(TokenOnWire.class, tw1);
SignedToken st = new SignedToken(reserialized, "badsignature");
byte[] serializedSignedToken = _serializer.toByteArray(SignedToken.class, st);
byte[] forgedToken = Base64.encodeBase64(serializedSignedToken);
// Resulting token should fail validation even though the embedded token data is good
try {
gotUser = _tokenManager.validateToken(new String(forgedToken, "UTF-8"));
Assert.fail("Resulting token should fail validation");
} catch (UnauthorizedException ex) {
// This is an expected exception
Assert.assertTrue(true);
}
try {
gotUser = _tokenManager.validateToken("somethingthatwontevendecode");
Assert.fail("Arbitrary token should not be validated.");
} catch (UnauthorizedException ex) {
// This is an expected exception.
Assert.assertTrue(true);
}
}
Aggregations