/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.usergrid.management.cassandra; import org.apache.usergrid.NewOrgAppAdminRule; import org.apache.usergrid.ServiceITSetup; import org.apache.usergrid.ServiceITSetupImpl; import org.apache.usergrid.cassandra.ClearShiroSubject; import org.apache.usergrid.cassandra.SpringResource; import org.apache.usergrid.count.SimpleBatcher; import org.apache.usergrid.management.OrganizationInfo; import org.apache.usergrid.management.UserInfo; import org.apache.usergrid.persistence.CredentialsInfo; import org.apache.usergrid.persistence.Entity; import org.apache.usergrid.persistence.EntityManager; import org.apache.usergrid.persistence.entities.User; import org.apache.usergrid.security.AuthPrincipalType; import org.apache.usergrid.security.crypto.command.Md5HashCommand; import org.apache.usergrid.security.crypto.command.Sha1HashCommand; import org.apache.usergrid.security.tokens.TokenCategory; import org.apache.usergrid.security.tokens.exceptions.InvalidTokenException; import org.apache.usergrid.utils.JsonUtils; import org.apache.usergrid.utils.UUIDUtils; import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.UUID; import static org.apache.commons.codec.binary.Base64.encodeBase64URLSafeString; import static org.apache.usergrid.TestHelper.*; import static org.apache.usergrid.persistence.Schema.DICTIONARY_CREDENTIALS; import static org.junit.Assert.*; /** * @author zznate */ public class ManagementServiceIT { private static final Logger logger = LoggerFactory.getLogger( ManagementServiceIT.class ); @ClassRule public static final ServiceITSetup setup = new ServiceITSetupImpl(); @Rule public ClearShiroSubject clearShiroSubject = new ClearShiroSubject(); @Rule public NewOrgAppAdminRule orgAppAdminRule = new NewOrgAppAdminRule( setup ); // app-level data generated only once private UserInfo adminUser; private UUID applicationId; @Before public void setup() throws Exception { logger.info( "in setup" ); adminUser = orgAppAdminRule.getAdminInfo(); applicationId = orgAppAdminRule.getApplicationInfo().getId(); setup.getEntityIndex().refresh(applicationId); } @Test public void testGetTokenForPrincipalAdmin() throws Exception { String token = ( ( ManagementServiceImpl ) setup.getMgmtSvc() ) .getTokenForPrincipal( TokenCategory.ACCESS, null, setup.getEmf().getManagementAppId(), AuthPrincipalType.ADMIN_USER, adminUser.getUuid(), 0 ); // ^ same as: // managementService.getAccessTokenForAdminUser(user.getUuid()); assertNotNull( token ); token = ( ( ManagementServiceImpl ) setup.getMgmtSvc() ) .getTokenForPrincipal( TokenCategory.ACCESS, null, setup.getEmf().getManagementAppId(), AuthPrincipalType.APPLICATION_USER, adminUser.getUuid(), 0 ); // This works because ManagementService#getSecret takes the same code // path // on an OR for APP._USER as for ADMIN_USER // is ok technically as ADMIN_USER is a APP_USER to the admin app, but // should still // be stricter checking assertNotNull( token ); // managementService.getTokenForPrincipal(appUuid, authPrincipal, pUuid, // salt, true); } @Test public void testGetTokenForPrincipalUser() throws Exception { // create a user Map<String, Object> properties = new LinkedHashMap<String, Object>(); properties.put( "username", "edanuff" ); properties.put( "email", "ed@anuff.com" ); Entity user = setup.getEmf().getEntityManager( applicationId ).create( "user", properties ); assertNotNull( user ); String token = ( ( ManagementServiceImpl ) setup.getMgmtSvc() ) .getTokenForPrincipal( TokenCategory.ACCESS, null, setup.getEmf().getManagementAppId(), AuthPrincipalType.APPLICATION_USER, user.getUuid(), 0 ); assertNotNull( token ); } @Test public void testCountAdminUserAction() throws Exception { SimpleBatcher batcher = SpringResource.getInstance().getBean( SimpleBatcher.class ); batcher.setBlockingSubmit( true ); batcher.setBatchSize( 1 ); EntityManager em = setup.getEmf().getEntityManager( setup.getEmf().getManagementAppId() ); Map<String, Long> counts = em.getApplicationCounters(); logger.info( JsonUtils.mapToJsonString( counts ) ); logger.info( JsonUtils.mapToJsonString( em.getCounterNames() ) ); final Long existingCounts = counts.get( "admin_logins" ); final long startCount = existingCounts == null ? 0 : existingCounts; setup.getMgmtSvc().countAdminUserAction( adminUser, "login" ); counts = em.getApplicationCounters(); logger.info( JsonUtils.mapToJsonString( counts ) ); logger.info( JsonUtils.mapToJsonString( em.getCounterNames() ) ); assertNotNull( counts.get( "admin_logins" ) ); final long newCount = counts.get( "admin_logins" ); assertEquals( 1l, newCount - startCount ); } @Test public void deactivateUser() throws Exception { UUID uuid = UUIDUtils.newTimeUUID(); Map<String, Object> properties = new LinkedHashMap<String, Object>(); properties.put( "username", "test" + uuid ); properties.put( "email", String.format( "test%s@anuff.com", uuid ) ); EntityManager em = setup.getEmf().getEntityManager( applicationId ); Entity entity = em.create( "user", properties ); assertNotNull( entity ); User user = em.get( entity.getUuid(), User.class ); assertFalse( user.activated() ); assertNull( user.getDeactivated() ); setup.getMgmtSvc().activateAppUser( applicationId, user.getUuid() ); setup.getEntityIndex().refresh(applicationId); user = em.get( entity.getUuid(), User.class ); assertTrue( user.activated() ); assertNull( user.getDeactivated() ); // get a couple of tokens. These shouldn't work after we deactive the user String token1 = setup.getMgmtSvc().getAccessTokenForAppUser( applicationId, user.getUuid(), 0 ); String token2 = setup.getMgmtSvc().getAccessTokenForAppUser( applicationId, user.getUuid(), 0 ); assertNotNull( setup.getTokenSvc().getTokenInfo( token1 ) ); assertNotNull( setup.getTokenSvc().getTokenInfo( token2 ) ); long startTime = System.currentTimeMillis(); setup.getMgmtSvc().deactivateUser( applicationId, user.getUuid() ); long endTime = System.currentTimeMillis(); user = em.get( entity.getUuid(), User.class ); assertFalse( user.activated() ); assertNotNull( user.getDeactivated() ); assertTrue( startTime <= user.getDeactivated() && user.getDeactivated() <= endTime ); boolean invalidTokenExcpetion = false; try { setup.getTokenSvc().getTokenInfo( token1 ); } catch ( InvalidTokenException ite ) { invalidTokenExcpetion = true; } assertTrue( invalidTokenExcpetion ); invalidTokenExcpetion = false; try { setup.getTokenSvc().getTokenInfo( token2 ); } catch ( InvalidTokenException ite ) { invalidTokenExcpetion = true; } assertTrue( invalidTokenExcpetion ); } @Test public void disableAdminUser() throws Exception { UUID uuid = UUIDUtils.newTimeUUID(); Map<String, Object> properties = new LinkedHashMap<String, Object>(); properties.put( "username", "test" + uuid ); properties.put( "email", String.format( "test%s@anuff.com", uuid ) ); EntityManager em = setup.getEmf().getEntityManager( setup.getEmf().getManagementAppId() ); Entity entity = em.create( "user", properties ); assertNotNull( entity ); User user = em.get( entity.getUuid(), User.class ); assertFalse( user.activated() ); assertNull( user.getDeactivated() ); setup.getMgmtSvc().activateAdminUser( user.getUuid() ); user = em.get( entity.getUuid(), User.class ); assertTrue( user.activated() ); assertNull( user.getDeactivated() ); // get a couple of tokens. These shouldn't work after we deactive the user String token1 = setup.getMgmtSvc().getAccessTokenForAdminUser( user.getUuid(), 0 ); String token2 = setup.getMgmtSvc().getAccessTokenForAdminUser( user.getUuid(), 0 ); assertNotNull( setup.getTokenSvc().getTokenInfo( token1 ) ); assertNotNull( setup.getTokenSvc().getTokenInfo( token2 ) ); setup.getMgmtSvc().disableAdminUser( user.getUuid() ); user = em.get( entity.getUuid(), User.class ); assertTrue( user.disabled() ); boolean invalidTokenExcpetion = false; try { setup.getTokenSvc().getTokenInfo( token1 ); } catch ( InvalidTokenException ite ) { invalidTokenExcpetion = true; } assertTrue( invalidTokenExcpetion ); invalidTokenExcpetion = false; try { setup.getTokenSvc().getTokenInfo( token2 ); } catch ( InvalidTokenException ite ) { invalidTokenExcpetion = true; } assertTrue( invalidTokenExcpetion ); } @Test public void userTokensRevoke() throws Exception { UUID userId = UUIDUtils.newTimeUUID(); String token1 = setup.getMgmtSvc().getAccessTokenForAppUser( applicationId, userId, 0 ); String token2 = setup.getMgmtSvc().getAccessTokenForAppUser( applicationId, userId, 0 ); assertNotNull( setup.getTokenSvc().getTokenInfo( token1 ) ); assertNotNull( setup.getTokenSvc().getTokenInfo( token2 ) ); setup.getMgmtSvc().revokeAccessTokensForAppUser( applicationId, userId ); boolean invalidTokenExcpetion = false; try { setup.getTokenSvc().getTokenInfo( token1 ); } catch ( InvalidTokenException ite ) { invalidTokenExcpetion = true; } assertTrue( invalidTokenExcpetion ); invalidTokenExcpetion = false; try { setup.getTokenSvc().getTokenInfo( token2 ); } catch ( InvalidTokenException ite ) { invalidTokenExcpetion = true; } assertTrue( invalidTokenExcpetion ); } @Test public void userTokenRevoke() throws Exception { EntityManager em = setup.getEmf().getEntityManager( applicationId ); Map<String, Object> properties = new LinkedHashMap<String, Object>(); properties.put( "username", "realbeast" ); properties.put( "email", "sungju@softwaregeeks.org" ); Entity user = em.create( "user", properties ); assertNotNull( user ); UUID userId = user.getUuid(); String token1 = setup.getMgmtSvc().getAccessTokenForAppUser( applicationId, userId, 0 ); String token2 = setup.getMgmtSvc().getAccessTokenForAppUser( applicationId, userId, 0 ); assertNotNull( setup.getTokenSvc().getTokenInfo( token1 ) ); assertNotNull( setup.getTokenSvc().getTokenInfo( token2 ) ); setup.getMgmtSvc().revokeAccessTokenForAppUser( token1 ); boolean invalidToken1Excpetion = false; try { setup.getTokenSvc().getTokenInfo( token1 ); } catch ( InvalidTokenException ite ) { invalidToken1Excpetion = true; } assertTrue( invalidToken1Excpetion ); boolean invalidToken2Excpetion = true; try { setup.getTokenSvc().getTokenInfo( token2 ); } catch ( InvalidTokenException ite ) { invalidToken2Excpetion = false; } assertTrue( invalidToken2Excpetion ); } @Test public void adminTokensRevoke() throws Exception { UUID userId = UUIDUtils.newTimeUUID(); String token1 = setup.getMgmtSvc().getAccessTokenForAdminUser( userId, 0 ); String token2 = setup.getMgmtSvc().getAccessTokenForAdminUser( userId, 0 ); assertNotNull( setup.getTokenSvc().getTokenInfo( token1 ) ); assertNotNull( setup.getTokenSvc().getTokenInfo( token2 ) ); setup.getMgmtSvc().revokeAccessTokensForAdminUser( userId ); boolean invalidTokenException = false; try { setup.getTokenSvc().getTokenInfo( token1 ); } catch ( InvalidTokenException ite ) { invalidTokenException = true; } assertTrue( invalidTokenException ); invalidTokenException = false; try { setup.getTokenSvc().getTokenInfo( token2 ); } catch ( InvalidTokenException ite ) { invalidTokenException = true; } assertTrue( invalidTokenException ); } @Test public void adminTokenRevoke() throws Exception { UUID userId = adminUser.getUuid(); String token1 = setup.getMgmtSvc().getAccessTokenForAdminUser( userId, 0 ); String token2 = setup.getMgmtSvc().getAccessTokenForAdminUser( userId, 0 ); assertNotNull( setup.getTokenSvc().getTokenInfo( token1 ) ); assertNotNull( setup.getTokenSvc().getTokenInfo( token2 ) ); setup.getMgmtSvc().revokeAccessTokenForAdminUser( userId, token1 ); boolean invalidToken1Excpetion = false; try { setup.getTokenSvc().getTokenInfo( token1 ); } catch ( InvalidTokenException ite ) { invalidToken1Excpetion = true; } assertTrue( invalidToken1Excpetion ); boolean invalidToken2Excpetion = true; try { setup.getTokenSvc().getTokenInfo( token2 ); } catch ( InvalidTokenException ite ) { invalidToken2Excpetion = false; } assertTrue( invalidToken2Excpetion ); } public void superUserGetOrganizationsPage() throws Exception { int beforeSize = setup.getMgmtSvc().getOrganizations().size() - 1; // create 15 orgs for ( int x = 0; x < 15; x++ ) { setup.getMgmtSvc().createOrganization( "super-user-org-" + x, adminUser, true ); } // should be 17 total assertEquals( 16 + beforeSize, setup.getMgmtSvc().getOrganizations().size() ); List<OrganizationInfo> orgs = setup.getMgmtSvc().getOrganizations( null, 10 ); assertEquals( 10, orgs.size() ); UUID val = orgs.get( 9 ).getUuid(); orgs = setup.getMgmtSvc().getOrganizations( val, 10 ); assertEquals( 7 + beforeSize, orgs.size() ); assertEquals( val, orgs.get( 0 ).getUuid() ); } @Test public void authenticateAdmin() throws Exception { String username = uniqueUsername(); String password = "test"; UserInfo adminUser = setup.getMgmtSvc() .createAdminUser( null, username, "Todd Nine",uniqueEmail(), password, false, false ); EntityManager em = setup.getEmf().getEntityManager( setup.getSmf().getManagementAppId() ); setup.getEntityIndex().refresh(applicationId); UserInfo authedUser = setup.getMgmtSvc().verifyAdminUserPasswordCredentials( username, password ); assertEquals( adminUser.getUuid(), authedUser.getUuid() ); authedUser = setup.getMgmtSvc().verifyAdminUserPasswordCredentials( adminUser.getEmail(), password ); assertEquals( adminUser.getUuid(), authedUser.getUuid() ); authedUser = setup.getMgmtSvc().verifyAdminUserPasswordCredentials( adminUser.getUuid().toString(), password ); assertEquals( adminUser.getUuid(), authedUser.getUuid() ); } /** * Test we can change the password if it's hashed with sha1 */ @Test public void testAdminPasswordChangeShaType() throws Exception { String username = uniqueUsername(); String password = "test"; User user = new User(); user.setActivated( true ); user.setUsername( username ); EntityManager em = setup.getEmf().getEntityManager( setup.getEmf().getManagementAppId() ); User storedUser = em.create( user ); UUID userId = storedUser.getUuid(); //set the password in the sha1 format CredentialsInfo info = new CredentialsInfo(); info.setRecoverable( false ); info.setEncrypted( true ); Sha1HashCommand command = new Sha1HashCommand(); byte[] hashed = command.hash( password.getBytes( "UTF-8" ), info, userId, setup.getEmf().getManagementAppId() ); info.setSecret( encodeBase64URLSafeString( hashed ) ); info.setCipher( command.getName() ); em.addToDictionary( storedUser, DICTIONARY_CREDENTIALS, "password", info ); setup.getEntityIndex().refresh(applicationId); //verify authorization works User authedUser = setup.getMgmtSvc().verifyAppUserPasswordCredentials( setup.getEmf().getManagementAppId(), username, password ); assertEquals( userId, authedUser.getUuid() ); //test we can change the password String newPassword = "test2"; setup.getMgmtSvc().setAppUserPassword( setup.getEmf().getManagementAppId(), userId, password, newPassword ); //verify authorization works authedUser = setup.getMgmtSvc().verifyAppUserPasswordCredentials( setup.getEmf().getManagementAppId(), username, newPassword ); assertEquals( userId, authedUser.getUuid() ); } /** * Test we can change the password if it's hashed with md5 then sha1 */ @Test public void testAdminPasswordChangeMd5ShaType() throws Exception { String username = uniqueUsername(); String password = "test"; User user = new User(); user.setActivated( true ); user.setUsername( username ); EntityManager em = setup.getEmf().getEntityManager( setup.getEmf().getManagementAppId() ); User storedUser = em.create( user ); setup.getEntityIndex().refresh(applicationId); UUID userId = storedUser.getUuid(); //set the password in the sha1 format //set the password in the sha1 format CredentialsInfo info = new CredentialsInfo(); info.setRecoverable( false ); info.setEncrypted( true ); Md5HashCommand md5 = new Md5HashCommand(); Sha1HashCommand sha1 = new Sha1HashCommand(); byte[] hashed = md5.hash( password.getBytes( "UTF-8" ), info, userId, setup.getEmf().getManagementAppId() ); hashed = sha1.hash( hashed, info, userId, setup.getEmf().getManagementAppId() ); info.setSecret( encodeBase64URLSafeString( hashed ) ); //set the final cipher to sha1 info.setCipher( sha1.getName() ); //set the next hash type to md5 info.setHashType( md5.getName() ); em.addToDictionary( storedUser, DICTIONARY_CREDENTIALS, "password", info ); //verify authorization works User authedUser = setup.getMgmtSvc().verifyAppUserPasswordCredentials( setup.getEmf().getManagementAppId(), username, password ); assertEquals( userId, authedUser.getUuid() ); //test we can change the password String newPassword = "test2"; setup.getMgmtSvc().setAppUserPassword( setup.getEmf().getManagementAppId(), userId, password, newPassword ); //verify authorization works authedUser = setup.getMgmtSvc().verifyAppUserPasswordCredentials( setup.getEmf().getManagementAppId(), username, newPassword ); assertEquals( userId, authedUser.getUuid() ); } @Test public void authenticateUser() throws Exception { String username = uniqueUsername(); String password = "test"; String orgName = uniqueOrg(); String appName = uniqueApp(); Entity appInfo = setup.getEmf().createApplicationV2( orgName, appName ); UUID appId = appInfo.getUuid(); User user = new User(); user.setActivated( true ); user.setUsername( username ); EntityManager em = setup.getEmf().getEntityManager( appId ); User storedUser = em.create( user ); setup.getEntityIndex().refresh(applicationId); UUID userId = storedUser.getUuid(); //set the password setup.getMgmtSvc().setAppUserPassword( appId, userId, password ); //verify authorization works User authedUser = setup.getMgmtSvc().verifyAppUserPasswordCredentials( appId, username, password ); assertEquals( userId, authedUser.getUuid() ); //test we can change the password String newPassword = "test2"; setup.getMgmtSvc().setAppUserPassword( appId, userId, password, newPassword ); setup.getEntityIndex().refresh(applicationId); //verify authorization works authedUser = setup.getMgmtSvc().verifyAppUserPasswordCredentials( appId, username, newPassword ); } /** * Test we can change the password if it's hashed with sha1 */ @Test public void testAppUserPasswordChangeShaType() throws Exception { String username = "tnine"+newUUIDString(); String password = "test"; String orgName = "testAppUserPasswordChangeShaType"+newUUIDString(); String appName = "testAppUserPasswordChangeShaType"+newUUIDString(); Entity appInfo = setup.getEmf().createApplicationV2(orgName, appName); UUID appId = appInfo.getUuid(); User user = new User(); user.setActivated( true ); user.setUsername( username ); EntityManager em = setup.getEmf().getEntityManager( appId ); User storedUser = em.create( user ); setup.getEntityIndex().refresh(applicationId); UUID userId = storedUser.getUuid(); //set the password in the sha1 format CredentialsInfo info = new CredentialsInfo(); info.setRecoverable( false ); info.setEncrypted( true ); Sha1HashCommand command = new Sha1HashCommand(); byte[] hashed = command.hash( password.getBytes( "UTF-8" ), info, userId, appId ); info.setSecret( encodeBase64URLSafeString( hashed ) ); info.setCipher( command.getName() ); em.addToDictionary( storedUser, DICTIONARY_CREDENTIALS, "password", info ); //verify authorization works User authedUser = setup.getMgmtSvc().verifyAppUserPasswordCredentials( appId, username, password ); assertEquals( userId, authedUser.getUuid() ); //test we can change the password String newPassword = "test2"; setup.getMgmtSvc().setAppUserPassword( appId, userId, password, newPassword ); setup.getEntityIndex().refresh(applicationId); //verify authorization works authedUser = setup.getMgmtSvc().verifyAppUserPasswordCredentials( appId, username, newPassword ); assertEquals( userId, authedUser.getUuid() ); } /** * Test we can change the password if it's hashed with md5 then sha1 */ @Test public void testAppUserPasswordChangeMd5ShaType() throws Exception { String username = uniqueUsername(); String password = "test"; String orgName = uniqueOrg(); String appName = uniqueApp(); Entity appInfo = setup.getEmf().createApplicationV2(orgName, appName); UUID appId = appInfo.getUuid(); User user = new User(); user.setActivated( true ); user.setUsername( username ); EntityManager em = setup.getEmf().getEntityManager( appId ); User storedUser = em.create( user ); setup.getEntityIndex().refresh(applicationId); UUID userId = storedUser.getUuid(); //set the password in the sha1 format CredentialsInfo info = new CredentialsInfo(); info.setRecoverable( false ); info.setEncrypted( true ); Md5HashCommand md5 = new Md5HashCommand(); Sha1HashCommand sha1 = new Sha1HashCommand(); byte[] hashed = md5.hash( password.getBytes( "UTF-8" ), info, userId, appId ); hashed = sha1.hash( hashed, info, userId, appId ); info.setSecret( encodeBase64URLSafeString( hashed ) ); //set the final cipher to sha1 info.setCipher( sha1.getName() ); //set the next hash type to md5 info.setHashType( md5.getName() ); em.addToDictionary( storedUser, DICTIONARY_CREDENTIALS, "password", info ); //verify authorization works User authedUser = setup.getMgmtSvc().verifyAppUserPasswordCredentials( appId, username, password ); assertEquals( userId, authedUser.getUuid() ); //test we can change the password String newPassword = "test2"; setup.getMgmtSvc().setAppUserPassword( appId, userId, password, newPassword ); setup.getEntityIndex().refresh(applicationId); //verify authorization works authedUser = setup.getMgmtSvc().verifyAppUserPasswordCredentials( appId, username, newPassword ); assertEquals( userId, authedUser.getUuid() ); } }