| // 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 com.cloud.acl; | |
| import org.apache.cloudstack.acl.ControlledEntity; | |
| import org.apache.cloudstack.acl.SecurityChecker; | |
| import org.junit.Test; | |
| import org.junit.runner.RunWith; | |
| import org.mockito.InjectMocks; | |
| import org.mockito.Mock; | |
| import org.mockito.Mockito; | |
| import org.mockito.Spy; | |
| import org.mockito.junit.MockitoJUnitRunner; | |
| import com.cloud.domain.dao.DomainDao; | |
| import com.cloud.exception.PermissionDeniedException; | |
| import com.cloud.projects.ProjectManager; | |
| import com.cloud.user.Account; | |
| import com.cloud.user.AccountService; | |
| import com.cloud.user.AccountVO; | |
| import com.cloud.user.dao.AccountDao; | |
| import com.cloud.utils.Ternary; | |
| @RunWith(MockitoJUnitRunner.class) | |
| public class DomainCheckerTest { | |
| @Mock | |
| AccountService _accountService; | |
| @Mock | |
| AccountDao _accountDao; | |
| @Mock | |
| DomainDao _domainDao; | |
| @Mock | |
| ProjectManager _projectMgr; | |
| @Spy | |
| @InjectMocks | |
| DomainChecker domainChecker; | |
| private ControlledEntity getMockedEntity(long accountId) { | |
| ControlledEntity entity = Mockito.mock(Account.class); | |
| Mockito.when(entity.getAccountId()).thenReturn(accountId); | |
| Mockito.when(entity.getEntityType()).thenReturn((Class)Account.class); | |
| return entity; | |
| } | |
| @Test | |
| public void testRootAdminHasAccess() { | |
| Account rootAdmin = Mockito.mock(Account.class); | |
| Mockito.when(rootAdmin.getId()).thenReturn(1L); | |
| ControlledEntity entity = getMockedEntity(2L); | |
| Mockito.when(_accountService.isRootAdmin(rootAdmin.getId())).thenReturn(true); | |
| domainChecker.validateCallerHasAccessToEntityOwner(rootAdmin, entity, SecurityChecker.AccessType.ModifyProject); | |
| } | |
| @Test | |
| public void testCallerIsOwner() { | |
| Account caller = Mockito.mock(Account.class); | |
| Mockito.when(caller.getId()).thenReturn(1L); | |
| ControlledEntity entity = getMockedEntity(1L); | |
| domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, SecurityChecker.AccessType.ModifyProject); | |
| } | |
| @Test(expected = PermissionDeniedException.class) | |
| public void testOwnerNotFound() { | |
| Account caller = Mockito.mock(Account.class); | |
| Mockito.when(caller.getId()).thenReturn(1L); | |
| ControlledEntity entity = getMockedEntity(2L); | |
| Mockito.when(_accountDao.findByIdIncludingRemoved(entity.getAccountId())).thenReturn(null); | |
| domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, SecurityChecker.AccessType.ModifyProject); | |
| } | |
| @Test | |
| public void testDomainAdminHasAccess() { | |
| Account caller = Mockito.mock(Account.class); | |
| Mockito.when(caller.getId()).thenReturn(1L); | |
| Mockito.when(caller.getDomainId()).thenReturn(100L); | |
| Mockito.when(caller.getType()).thenReturn(Account.Type.DOMAIN_ADMIN); | |
| ControlledEntity entity = getMockedEntity(2L); | |
| AccountVO owner = Mockito.mock(AccountVO.class); | |
| Mockito.when(owner.getDomainId()).thenReturn(101L); | |
| Mockito.when(_accountDao.findByIdIncludingRemoved(entity.getAccountId())).thenReturn(owner); | |
| Mockito.when(_domainDao.isChildDomain(100L, 101L)).thenReturn(true); | |
| domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, SecurityChecker.AccessType.ModifyProject); | |
| } | |
| @Test | |
| public void testDomainAdminHasAccessToRemovedOwner() { | |
| Account caller = Mockito.mock(Account.class); | |
| Mockito.when(caller.getId()).thenReturn(1L); | |
| Mockito.when(caller.getDomainId()).thenReturn(100L); | |
| Mockito.when(caller.getType()).thenReturn(Account.Type.DOMAIN_ADMIN); | |
| ControlledEntity entity = getMockedEntity(2L); | |
| AccountVO removedOwner = Mockito.mock(AccountVO.class); | |
| Mockito.when(removedOwner.getDomainId()).thenReturn(101L); | |
| Mockito.when(_accountDao.findByIdIncludingRemoved(entity.getAccountId())).thenReturn(removedOwner); | |
| Mockito.when(_domainDao.isChildDomain(100L, 101L)).thenReturn(true); | |
| domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, SecurityChecker.AccessType.ModifyProject); | |
| } | |
| private Ternary<Account, ControlledEntity, AccountVO> getProjectAccessCheckResources() { | |
| Account caller = Mockito.mock(Account.class); | |
| Mockito.when(caller.getId()).thenReturn(100L); | |
| Mockito.when(caller.getType()).thenReturn(Account.Type.PROJECT); | |
| ControlledEntity entity = getMockedEntity(2L); | |
| AccountVO projectAccount = Mockito.mock(AccountVO.class); | |
| Mockito.when(projectAccount.getId()).thenReturn(2L); | |
| Mockito.when(projectAccount.getType()).thenReturn(Account.Type.PROJECT); | |
| return new Ternary<>(caller, entity, projectAccount); | |
| } | |
| @Test | |
| public void testProjectOwnerCanModify() { | |
| Ternary<Account, ControlledEntity, AccountVO> resources = getProjectAccessCheckResources(); | |
| Account caller = resources.first(); | |
| ControlledEntity entity = resources.second(); | |
| AccountVO projectAccount = resources.third(); | |
| Mockito.when(_accountDao.findByIdIncludingRemoved(entity.getAccountId())).thenReturn(projectAccount); | |
| Mockito.when(_projectMgr.canModifyProjectAccount(caller, projectAccount.getId())).thenReturn(true); | |
| Mockito.doReturn(true).when(domainChecker).checkOperationPermitted(caller, entity); | |
| domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, SecurityChecker.AccessType.ModifyProject); | |
| } | |
| @Test(expected = PermissionDeniedException.class) | |
| public void testProjectOwnerCannotModify() { | |
| Ternary<Account, ControlledEntity, AccountVO> resources = getProjectAccessCheckResources(); | |
| Account caller = resources.first(); | |
| ControlledEntity entity = resources.second(); | |
| AccountVO projectAccount = resources.third(); | |
| Mockito.when(_accountDao.findByIdIncludingRemoved(entity.getAccountId())).thenReturn(projectAccount); | |
| Mockito.when(_projectMgr.canModifyProjectAccount(caller, projectAccount.getId())).thenReturn(false); | |
| domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, SecurityChecker.AccessType.ModifyProject); | |
| } | |
| @Test | |
| public void testProjectOwnerCanAccess() { | |
| Ternary<Account, ControlledEntity, AccountVO> resources = getProjectAccessCheckResources(); | |
| Account caller = resources.first(); | |
| ControlledEntity entity = resources.second(); | |
| AccountVO projectAccount = resources.third(); | |
| Mockito.when(_accountDao.findByIdIncludingRemoved(entity.getAccountId())).thenReturn(projectAccount); | |
| Mockito.when(_projectMgr.canAccessProjectAccount(caller, projectAccount.getId())).thenReturn(true); | |
| Mockito.doReturn(true).when(domainChecker).checkOperationPermitted(caller, entity); | |
| domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, SecurityChecker.AccessType.ListEntry); | |
| } | |
| @Test(expected = PermissionDeniedException.class) | |
| public void testProjectOwnerCannotAccess() { | |
| Ternary<Account, ControlledEntity, AccountVO> resources = getProjectAccessCheckResources(); | |
| Account caller = resources.first(); | |
| ControlledEntity entity = resources.second(); | |
| AccountVO projectAccount = resources.third(); | |
| Mockito.when(_accountDao.findByIdIncludingRemoved(entity.getAccountId())).thenReturn(projectAccount); | |
| Mockito.when(_projectMgr.canAccessProjectAccount(caller, projectAccount.getId())).thenReturn(false); | |
| domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, SecurityChecker.AccessType.ListEntry); | |
| } | |
| } |