content: // 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.findById(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.findById(entity.getAccountId())).thenReturn(owner);
          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.findById(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.findById(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.findById(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.findById(entity.getAccountId())).thenReturn(projectAccount);
          Mockito.when(_projectMgr.canAccessProjectAccount(caller, projectAccount.getId())).thenReturn(false);
  
          domainChecker.validateCallerHasAccessToEntityOwner(caller, entity, SecurityChecker.AccessType.ListEntry);
      }
  
  }
  