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 org.apache.cloudstack.api.command;
  
  import static org.mockito.ArgumentMatchers.anyString;
  import static org.mockito.ArgumentMatchers.nullable;
  
  import java.lang.reflect.Field;
  import java.net.InetAddress;
  import java.util.HashMap;
  import java.util.Map;
  
  import javax.servlet.http.Cookie;
  import javax.servlet.http.HttpServletRequest;
  import javax.servlet.http.HttpServletResponse;
  import javax.servlet.http.HttpSession;
  
  import org.apache.cloudstack.api.ApiConstants;
  import org.apache.cloudstack.api.ApiErrorCode;
  import org.apache.cloudstack.api.ApiServerService;
  import org.apache.cloudstack.api.BaseCmd;
  import org.apache.cloudstack.api.ServerApiException;
  import org.apache.cloudstack.api.auth.APIAuthenticationType;
  import org.apache.cloudstack.api.response.LoginCmdResponse;
  import org.apache.cloudstack.saml.SAML2AuthManager;
  import org.junit.Assert;
  import org.junit.Test;
  import org.junit.runner.RunWith;
  import org.mockito.Mock;
  import org.mockito.Mockito;
  import org.mockito.junit.MockitoJUnitRunner;
  
  import com.cloud.domain.DomainVO;
  import com.cloud.domain.dao.DomainDao;
  import com.cloud.user.Account;
  import com.cloud.user.AccountService;
  import com.cloud.user.User;
  import com.cloud.user.UserAccountVO;
  import com.cloud.user.UserVO;
  import com.cloud.user.dao.UserAccountDao;
  import com.cloud.user.dao.UserDao;
  import com.cloud.utils.HttpUtils;
  
  import junit.framework.TestCase;
  
  @RunWith(MockitoJUnitRunner.class)
  public class ListAndSwitchSAMLAccountCmdTest extends TestCase {
      @Mock
      ApiServerService apiServer;
  
      @Mock
      SAML2AuthManager samlAuthManager;
  
      @Mock
      AccountService accountService;
  
      @Mock
      UserAccountDao userAccountDao;
  
      @Mock
      UserDao userDao;
  
      @Mock
      DomainDao domainDao;
  
      @Mock
      HttpSession session;
  
      @Mock
      HttpServletResponse resp;
  
      @Mock
      HttpServletRequest req;
  
      final String sessionId = "node0xxxxxxxxxxxxx";
      Cookie[] cookies;
  
      @Test
      public void testListAndSwitchSAMLAccountCmd() throws Exception {
          // Setup
          final Map<String, Object[]> params = new HashMap<String, Object[]>();
          final String sessionKeyValue = "someSessionIDValue";
          Mockito.when(session.getAttribute(ApiConstants.SESSIONKEY)).thenReturn(sessionKeyValue);
          Mockito.when(session.getAttribute("userid")).thenReturn(2L);
          Mockito.when(session.getId()).thenReturn(sessionId);
          params.put(ApiConstants.USER_ID, new String[]{"2"});
          params.put(ApiConstants.DOMAIN_ID, new String[]{"1"});
          Mockito.when(userDao.findByUuid(anyString())).thenReturn(new UserVO(2L));
          Mockito.when(domainDao.findByUuid(anyString())).thenReturn(new DomainVO());
  
          // Mock/field setup
          ListAndSwitchSAMLAccountCmd cmd = new ListAndSwitchSAMLAccountCmd();
          Field apiServerField = ListAndSwitchSAMLAccountCmd.class.getDeclaredField("_apiServer");
          apiServerField.setAccessible(true);
          apiServerField.set(cmd, apiServer);
  
          Field managerField = ListAndSwitchSAMLAccountCmd.class.getDeclaredField("_samlAuthManager");
          managerField.setAccessible(true);
          managerField.set(cmd, samlAuthManager);
  
          Field accountServiceField = BaseCmd.class.getDeclaredField("_accountService");
          accountServiceField.setAccessible(true);
          accountServiceField.set(cmd, accountService);
  
          Field userAccountDaoField = ListAndSwitchSAMLAccountCmd.class.getDeclaredField("_userAccountDao");
          userAccountDaoField.setAccessible(true);
          userAccountDaoField.set(cmd, userAccountDao);
  
          Field userDaoField = ListAndSwitchSAMLAccountCmd.class.getDeclaredField("_userDao");
          userDaoField.setAccessible(true);
          userDaoField.set(cmd, userDao);
  
          Field domainDaoField = ListAndSwitchSAMLAccountCmd.class.getDeclaredField("_domainDao");
          domainDaoField.setAccessible(true);
          domainDaoField.set(cmd, domainDao);
  
          // invalid session test
          try {
              cmd.authenticate("command", params, null, null, HttpUtils.RESPONSE_TYPE_JSON, new StringBuilder(), req, resp);
          } catch (ServerApiException exception) {
              assertEquals(exception.getErrorCode(), ApiErrorCode.UNAUTHORIZED);
          } finally {
              Mockito.verify(accountService, Mockito.times(0)).getUserAccountById(Mockito.anyLong());
          }
  
          // invalid sessionkey value test
          params.put(ApiConstants.SESSIONKEY, new String[]{"someOtherValue"});
          try {
              Mockito.when(session.isNew()).thenReturn(false);
              cmd.authenticate("command", params, session, null, HttpUtils.RESPONSE_TYPE_JSON, new StringBuilder(), req, resp);
          } catch (ServerApiException exception) {
              assertEquals(exception.getErrorCode(), ApiErrorCode.UNAUTHORIZED);
          } finally {
              Mockito.verify(accountService, Mockito.times(0)).getUserAccountById(Mockito.anyLong());
          }
  
          // valid sessionkey value and invalid JSESSIONID test
          cookies = new Cookie[2];
          cookies[0] = new Cookie(ApiConstants.SESSIONKEY, sessionKeyValue);
          cookies[1] = new Cookie("JSESSIONID", "invalid-JSESSIONID");
          Mockito.when(req.getCookies()).thenReturn(cookies);
          params.put(ApiConstants.SESSIONKEY, new String[]{sessionKeyValue});
          try {
              cmd.authenticate("command", params, session, null, HttpUtils.RESPONSE_TYPE_JSON, new StringBuilder(), req, resp);
          } catch (ServerApiException exception) {
              assertEquals(exception.getErrorCode(), ApiErrorCode.UNAUTHORIZED);
          } finally {
              Mockito.verify(accountService, Mockito.times(0)).getUserAccountById(Mockito.anyLong());
          }
  
          // valid sessionkey value and valid JSESSIONID test
          cookies = new Cookie[2];
          cookies[0] = new Cookie(ApiConstants.SESSIONKEY, sessionKeyValue);
          cookies[1] = new Cookie("JSESSIONID", sessionId + ".node0");
          Mockito.when(req.getCookies()).thenReturn(cookies);
          params.put(ApiConstants.SESSIONKEY, new String[]{sessionKeyValue});
          try {
              cmd.authenticate("command", params, session, null, HttpUtils.RESPONSE_TYPE_JSON, new StringBuilder(), req, resp);
          } catch (ServerApiException exception) {
              assertEquals(exception.getErrorCode(), ApiErrorCode.ACCOUNT_ERROR);
          } finally {
              Mockito.verify(accountService, Mockito.times(1)).getUserAccountById(Mockito.anyLong());
          }
  
          // valid sessionkey, invalid useraccount type (non-saml) value test
          UserAccountVO mockedUserAccount = new UserAccountVO();
          mockedUserAccount.setId(2L);
          mockedUserAccount.setAccountState(Account.State.ENABLED.toString());
          mockedUserAccount.setUsername("someUsername");
          mockedUserAccount.setExternalEntity("some IDP ID");
          mockedUserAccount.setDomainId(0L);
          mockedUserAccount.setSource(User.Source.UNKNOWN);
          Mockito.when(accountService.getUserAccountById(Mockito.anyLong())).thenReturn(mockedUserAccount);
          try {
              cmd.authenticate("command", params, session, null, HttpUtils.RESPONSE_TYPE_JSON, new StringBuilder(), req, resp);
          } catch (ServerApiException exception) {
              assertEquals(exception.getErrorCode(), ApiErrorCode.ACCOUNT_ERROR);
          } finally {
              // accountService should have been called twice by now, for this case and the case above
              Mockito.verify(accountService, Mockito.times(2)).getUserAccountById(Mockito.anyLong());
          }
  
          // all valid test
          mockedUserAccount.setSource(User.Source.SAML2);
          Mockito.when(accountService.getUserAccountById(Mockito.anyLong())).thenReturn(mockedUserAccount);
          Mockito.when(apiServer.verifyUser(Mockito.anyLong())).thenReturn(true);
          LoginCmdResponse loginCmdResponse = new LoginCmdResponse();
          loginCmdResponse.setUserId("1");
          loginCmdResponse.setDomainId("1");
          loginCmdResponse.setType("1");
          loginCmdResponse.setUsername("userName");
          loginCmdResponse.setAccount("someAccount");
          loginCmdResponse.setFirstName("firstName");
          loginCmdResponse.setLastName("lastName");
          loginCmdResponse.setSessionKey("newSessionKeyString");
          loginCmdResponse.set2FAenabled("false");
          Mockito.when(apiServer.loginUser(nullable(HttpSession.class), nullable(String.class), nullable(String.class),
                  nullable(Long.class), nullable(String.class), nullable(InetAddress.class), nullable(Map.class))).thenReturn(loginCmdResponse);
          try {
              cmd.authenticate("command", params, session, null, HttpUtils.RESPONSE_TYPE_JSON, new StringBuilder(), req, resp);
          } catch (ServerApiException exception) {
              fail("SAML list and switch account API failed to pass for all valid data: " + exception.getMessage());
          } finally {
              // accountService should have been called 4 times by now, for this case twice and 2 for cases above
              Mockito.verify(accountService, Mockito.times(4)).getUserAccountById(Mockito.anyLong());
          }
      }
  
      @Test
      public void testGetAPIType() {
          Assert.assertTrue(new ListAndSwitchSAMLAccountCmd().getAPIType() == APIAuthenticationType.READONLY_API);
      }
  
  }
  