ServiceAccountsService { public ResponseEntity<String> onboardServiceAccount(String token, ServiceAccount serviceAccount, UserDetails userDetails) { List<String> onboardedList = getOnboardedServiceAccountList(token, userDetails); if (onboardedList.contains(serviceAccount.getName())) { log.error(JSONUtil.getJSON(ImmutableMap.<String, String>builder(). put(LogMessage.USER, ThreadLocalContext.getCurrentMap().get(LogMessage.USER).toString()). put(LogMessage.ACTION, "onboardServiceAccount"). put(LogMessage.MESSAGE, "Failed to onboard Service Account. Service account is already onboarded"). put(LogMessage.APIURL, ThreadLocalContext.getCurrentMap().get(LogMessage.APIURL).toString()). build())); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("{\"errors\":[\"Failed to onboard Service Account. Service account is already onboarded\"]}"); } List<ADServiceAccount> allServiceAccounts = getADServiceAccount(serviceAccount.getName()); if (allServiceAccounts == null || allServiceAccounts.isEmpty()) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("{\"errors\":[\"Failed to onboard Service Account. Unable to read Service account details\"]}"); } if (TVaultConstants.EXPIRED.toLowerCase().equals(allServiceAccounts.get(0).getAccountStatus().toLowerCase())) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("{\"errors\":[\"Failed to onboard Service Account. Service account expired\"]}"); } int maxPwdAge = allServiceAccounts.get(0).getMaxPwdAge(); serviceAccount.setOwner(allServiceAccounts.get(0).getOwner()); if (serviceAccount.isAutoRotate()) { log.debug(JSONUtil.getJSON(ImmutableMap.<String, String>builder(). put(LogMessage.USER, ThreadLocalContext.getCurrentMap().get(LogMessage.USER).toString()). put(LogMessage.ACTION, "onboardServiceAccount"). put(LogMessage.MESSAGE, String.format ("Auto-Rotate of password has been turned on")). put(LogMessage.APIURL, ThreadLocalContext.getCurrentMap().get(LogMessage.APIURL).toString()). build())); if (null == serviceAccount.getMax_ttl()) { return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("{\"errors\":[\"Invalid or no value has been provided for MAX_TTL\"]}"); } if (null == serviceAccount.getTtl()) { serviceAccount.setTtl(maxPwdAge - 1L); } if (serviceAccount.getTtl() > maxPwdAge) { log.error(JSONUtil.getJSON(ImmutableMap.<String, String>builder(). put(LogMessage.USER, ThreadLocalContext.getCurrentMap().get(LogMessage.USER).toString()). put(LogMessage.ACTION, "onboardServiceAccount"). put(LogMessage.MESSAGE, String.format ("Password Expiration Time [%s] is greater the Maximum expiration time (MAX_TTL) [%s]", serviceAccount.getTtl(), maxPwdAge)). put(LogMessage.APIURL, ThreadLocalContext.getCurrentMap().get(LogMessage.APIURL).toString()). build())); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("{\"errors\":[\"Invalid value provided for Password Expiration Time. This can't be more than "+maxPwdAge+" for this Service Account\"]}"); } if (serviceAccount.getTtl() > serviceAccount.getMax_ttl()) { log.error(JSONUtil.getJSON(ImmutableMap.<String, String>builder(). put(LogMessage.USER, ThreadLocalContext.getCurrentMap().get(LogMessage.USER).toString()). put(LogMessage.ACTION, "onboardServiceAccount"). put(LogMessage.MESSAGE, String.format ("Password Expiration Time [%s] is greater the Maximum expiration time (MAX_TTL) [%s]", serviceAccount.getTtl(), serviceAccount.getMax_ttl())). put(LogMessage.APIURL, ThreadLocalContext.getCurrentMap().get(LogMessage.APIURL).toString()). build())); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("{\"errors\":[\"Password Expiration Time can't be more than Maximum expiration time (MAX_TTL) for this Service Account\"]}"); } } else { log.debug(JSONUtil.getJSON(ImmutableMap.<String, String>builder(). put(LogMessage.USER, ThreadLocalContext.getCurrentMap().get(LogMessage.USER).toString()). put(LogMessage.ACTION, "onboardServiceAccount"). put(LogMessage.MESSAGE, String.format ("Auto-Rotate of password has been turned off")). put(LogMessage.APIURL, ThreadLocalContext.getCurrentMap().get(LogMessage.APIURL).toString()). build())); serviceAccount.setTtl(TVaultConstants.MAX_TTL); } ResponseEntity<String> accountRoleCreationResponse = createAccountRole(token, serviceAccount); if(accountRoleCreationResponse.getStatusCode().equals(HttpStatus.OK)) { ResponseEntity<String> metadataCreationResponse = createMetadata(token, serviceAccount); if (HttpStatus.OK.equals(metadataCreationResponse.getStatusCode())) { log.debug(JSONUtil.getJSON(ImmutableMap.<String, String>builder(). put(LogMessage.USER, ThreadLocalContext.getCurrentMap().get(LogMessage.USER).toString()). put(LogMessage.ACTION, "onboardServiceAccount"). put(LogMessage.MESSAGE, String.format ("Successfully created Metadata for the Service Account")). put(LogMessage.APIURL, ThreadLocalContext.getCurrentMap().get(LogMessage.APIURL).toString()). build())); } else { log.error(JSONUtil.getJSON(ImmutableMap.<String, String>builder(). put(LogMessage.USER, ThreadLocalContext.getCurrentMap().get(LogMessage.USER).toString()). put(LogMessage.ACTION, "onboardServiceAccount"). put(LogMessage.MESSAGE, String.format ("Successfully created Service Account Role. However creation of Metadata failed.")). put(LogMessage.APIURL, ThreadLocalContext.getCurrentMap().get(LogMessage.APIURL).toString()). build())); return ResponseEntity.status(HttpStatus.MULTI_STATUS).body("{\"errors\":[\"Successfully created Service Account Role. However creation of Metadata failed.\"]}"); } String svcAccName = serviceAccount.getName(); ResponseEntity<String> svcAccPolicyCreationResponse = createServiceAccountPolicies(token, svcAccName); if (HttpStatus.OK.equals(svcAccPolicyCreationResponse.getStatusCode())) { ServiceAccountUser serviceAccountUser = new ServiceAccountUser(svcAccName, serviceAccount.getOwner(), TVaultConstants.SUDO_POLICY); ResponseEntity<String> addUserToServiceAccountResponse = addUserToServiceAccount(token, serviceAccountUser, userDetails, true); if (HttpStatus.OK.equals(addUserToServiceAccountResponse.getStatusCode())) { log.debug(JSONUtil.getJSON(ImmutableMap.<String, String>builder(). put(LogMessage.USER, ThreadLocalContext.getCurrentMap().get(LogMessage.USER).toString()). put(LogMessage.ACTION, "onboardServiceAccount"). put(LogMessage.MESSAGE, String.format ("Successfully completed onboarding of AD service account into TVault for password rotation.")). put(LogMessage.APIURL, ThreadLocalContext.getCurrentMap().get(LogMessage.APIURL).toString()). build())); String filterQuery = "(&(objectclass=user)(|(cn=" + serviceAccount.getOwner() + ")))"; List<ADUserAccount> managerDetails = getServiceAccountManagerDetails(filterQuery); if (!managerDetails.isEmpty() && !StringUtils.isEmpty(managerDetails.get(0).getUserEmail())) { String from = supportEmail; List<String> to = new ArrayList<>(); to.add(managerDetails.get(0).getUserEmail()); String mailSubject = String.format(subject, svcAccName); String groupContent = TVaultConstants.EMPTY; Map<String, String> mailTemplateVariables = new Hashtable<>(); mailTemplateVariables.put("name", managerDetails.get(0).getDisplayName()); mailTemplateVariables.put("svcAccName", svcAccName); if (serviceAccount.getAdGroup() != null && serviceAccount.getAdGroup() != "") { groupContent = String.format(mailAdGroupContent, serviceAccount.getAdGroup()); } mailTemplateVariables.put("groupContent", groupContent); mailTemplateVariables.put("contactLink", supportEmail); emailUtils.sendHtmlEmalFromTemplate(from, to, mailSubject, mailTemplateVariables); } return ResponseEntity.status(HttpStatus.OK).body("{\"messages\":[\"Successfully completed onboarding of AD service account into TVault for password rotation.\"]}"); } else { log.debug(JSONUtil.getJSON(ImmutableMap.<String, String>builder(). put(LogMessage.USER, ThreadLocalContext.getCurrentMap().get(LogMessage.USER).toString()). put(LogMessage.ACTION, "onboardServiceAccount"). put(LogMessage.MESSAGE, String.format ("Successfully created Service Account Role and policies. However the association of owner information failed.")). put(LogMessage.APIURL, ThreadLocalContext.getCurrentMap().get(LogMessage.APIURL).toString()). build())); return ResponseEntity.status(HttpStatus.MULTI_STATUS).body("{\"messages\":[\"Successfully created Service Account Role and policies. However the association of owner information failed.\"]}"); } } else { log.error(JSONUtil.getJSON(ImmutableMap.<String, String>builder(). put(LogMessage.USER, ThreadLocalContext.getCurrentMap().get(LogMessage.USER).toString()). put(LogMessage.ACTION, "onboardServiceAccount"). put(LogMessage.MESSAGE, String.format ("Failed to onboard AD service account into TVault for password rotation.")). put(LogMessage.APIURL, ThreadLocalContext.getCurrentMap().get(LogMessage.APIURL).toString()). build())); OnboardedServiceAccount serviceAccountToRevert = new OnboardedServiceAccount(serviceAccount.getName(),serviceAccount.getOwner()); ResponseEntity<String> accountRoleDeletionResponse = deleteAccountRole(token, serviceAccountToRevert); if (accountRoleDeletionResponse!=null && HttpStatus.OK.equals(accountRoleDeletionResponse.getStatusCode())) { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("{\"errors\":[\"Failed to onboard AD service account into TVault for password rotation.\"]}"); } else { return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("{\"errors\":[\"Failed to create Service Account policies. Revert service account role creation failed.\"]}"); } } } else { log.error(JSONUtil.getJSON(ImmutableMap.<String, String>builder(). put(LogMessage.USER, ThreadLocalContext.getCurrentMap().get(LogMessage.USER).toString()). put(LogMessage.ACTION, "onboardServiceAccount"). put(LogMessage.MESSAGE, String.format ("Failed to onboard AD service account into TVault for password rotation.")). put(LogMessage.APIURL, ThreadLocalContext.getCurrentMap().get(LogMessage.APIURL).toString()). build())); return ResponseEntity.status(HttpStatus.BAD_REQUEST).body("{\"errors\":[\"Failed to onboard AD service account into TVault for password rotation.\"]}"); } }  ResponseEntity<ADServiceAccountObjects> getADServiceAccounts(String token, UserDetails userDetails, String UserPrincipalName, boolean excludeOnboarded); ResponseEntity<String> onboardServiceAccount(String token, ServiceAccount serviceAccount, UserDetails userDetails); ResponseEntity<String> offboardServiceAccount(String token, OnboardedServiceAccount serviceAccount, UserDetails userDetails); ResponseEntity<String> addUserToServiceAccount(String token, ServiceAccountUser serviceAccountUser, UserDetails userDetails, boolean isPartOfSvcAccOnboard); ResponseEntity<String> removeUserFromServiceAccount(String token, ServiceAccountUser serviceAccountUser, UserDetails userDetails); ResponseEntity<String> resetSvcAccPassword(String token, String svcAccName, UserDetails userDetails); ResponseEntity<String> readSvcAccPassword(String token, String svcAccName, UserDetails userDetails); ResponseEntity<String> getOnboarderdServiceAccount(String token, String svcAccName, UserDetails userDetails); boolean canAddOrRemoveUser(UserDetails userDetails, ServiceAccountUser serviceAccountUser, String action); ResponseEntity<String> getOnboardedServiceAccounts(String token,  UserDetails userDetails); boolean hasAddOrRemovePermission(UserDetails userDetails, String serviceAccount, String token); boolean hasAddUserPermission(UserDetails userDetails, String serviceAccount, String token, boolean isPartOfSvcAccOnboard); static boolean isSvcaccPermissionInputValid(String access); ResponseEntity<String> addGroupToServiceAccount(String token, ServiceAccountGroup serviceAccountGroup, UserDetails userDetails); ResponseEntity<String> removeGroupFromServiceAccount(String token, ServiceAccountGroup serviceAccountGroup, UserDetails userDetails); ResponseEntity<String> associateApproletoSvcAcc(UserDetails userDetails, String token, ServiceAccountApprole serviceAccountApprole); ResponseEntity<String> getServiceAccountMeta(String token, UserDetails userDetails, String path); ResponseEntity<String> removeApproleFromSvcAcc(UserDetails userDetails, String token, ServiceAccountApprole serviceAccountApprole); ResponseEntity<String> addAwsRoleToSvcacc(UserDetails userDetails, String token, ServiceAccountAWSRole serviceAccountAWSRole); ResponseEntity<String> removeAWSRoleFromSvcacc(UserDetails userDetails, String token, ServiceAccountAWSRole serviceAccountAWSRole); ResponseEntity<String> createAWSRole(UserDetails userDetails, String token, AWSLoginRole awsLoginRole); ResponseEntity<String> createIAMRole(UserDetails userDetails, String token, AWSIAMRole awsiamRole); ResponseEntity<String> updateOnboardedServiceAccount(String token, ServiceAccount serviceAccount, UserDetails userDetails); ResponseEntity<String> transferSvcAccountOwner(UserDetails userDetails, String token, String svcAccName); ResponseEntity<String> getServiceAccounts(UserDetails userDetails, String userToken);  }
@Test public void test_onboardServiceAccount_failure_already_onboarded() { UserDetails userDetails = getMockUser(true); String token = userDetails.getClientToken(); ServiceAccount serviceAccount = generateServiceAccount("testacc02","testacc01"); serviceAccount.setAutoRotate(true); serviceAccount.setTtl(89L); serviceAccount.setMax_ttl(90L); Response response = getMockResponse(HttpStatus.OK, true, "{\"keys\":[\"testacc02\"]}"); when(reqProcessor.process("/ad/serviceaccount/onboardedlist","{}",token)).thenReturn(response); String expectedResponse = "{\"errors\":[\"Failed to onboard Service Account. Service account is already onboarded\"]}"; ResponseEntity<String> responseEntityExpected = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(expectedResponse); List<ADServiceAccount> allServiceAccounts = new ArrayList<>(); allServiceAccounts.add(generateADServiceAccount("testacc02")); ReflectionTestUtils.setField(serviceAccountsService, "ldapTemplate", ldapTemplate); when(ldapTemplate.search(Mockito.anyString(), Mockito.any(), Mockito.any(AttributesMapper.class))).thenReturn(null); ResponseEntity<String> responseEntity = serviceAccountsService.onboardServiceAccount(token, serviceAccount, userDetails); assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); assertEquals(responseEntityExpected, responseEntity); }
@Test public void test_onboardServiceAccount_failure_to_read_ad_details() { UserDetails userDetails = getMockUser(true); String token = userDetails.getClientToken(); ServiceAccount serviceAccount = generateServiceAccount("testacc02","testacc01"); Response response = getMockResponse(HttpStatus.OK, true, "{\"keys\":[\"testacc03\"]}"); when(reqProcessor.process("/ad/serviceaccount/onboardedlist","{}",token)).thenReturn(response); String expectedResponse = "{\"errors\":[\"Failed to onboard Service Account. Unable to read Service account details\"]}"; ResponseEntity<String> responseEntityExpected = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(expectedResponse); ReflectionTestUtils.setField(serviceAccountsService, "ldapTemplate", ldapTemplate); when(ldapTemplate.search(Mockito.anyString(), Mockito.any(), Mockito.any(AttributesMapper.class))).thenReturn(null); ResponseEntity<String> responseEntity = serviceAccountsService.onboardServiceAccount(token, serviceAccount, userDetails); assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); assertEquals(responseEntityExpected, responseEntity); }
@Test public void test_onboardServiceAccount_succss_autorotate_on_ttl_biggerthan_maxttl() { UserDetails userDetails = getMockUser(true); String token = userDetails.getClientToken(); ServiceAccount serviceAccount = generateServiceAccount("testacc02","testacc01"); serviceAccount.setAutoRotate(true); serviceAccount.setTtl(90L); serviceAccount.setMax_ttl(89L); ServiceAccountTTL serviceAccountTTL = new ServiceAccountTTL(); serviceAccountTTL.setRole_name(serviceAccount.getName()); serviceAccountTTL.setService_account_name(serviceAccount.getName() + "@null") ; serviceAccountTTL.setTtl(serviceAccount.getTtl()); String expectedResponse = "{\"errors\":[\"Password Expiration Time can't be more than Maximum expiration time (MAX_TTL) for this Service Account\"]}"; ResponseEntity<String> responseEntityExpected = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(expectedResponse); Response response = getMockResponse(HttpStatus.OK, true, "{\"keys\":[\"testacc03\"]}"); when(reqProcessor.process(Mockito.anyString(),Mockito.anyObject(),Mockito.anyString())).thenReturn(response); when(JSONUtil.getJSON((ServiceAccountTTL)Mockito.any())).thenReturn(getJSON(serviceAccountTTL)); List<ADServiceAccount> allServiceAccounts = new ArrayList<>(); allServiceAccounts.add(generateADServiceAccount("testacc02")); ReflectionTestUtils.setField(serviceAccountsService, "ldapTemplate", ldapTemplate); when(ldapTemplate.search(Mockito.anyString(), Mockito.any(), Mockito.any(AttributesMapper.class))).thenReturn(allServiceAccounts); ResponseEntity<String> responseEntity = serviceAccountsService.onboardServiceAccount(token, serviceAccount, userDetails); assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); assertEquals(responseEntityExpected, responseEntity); }
@Test public void test_onboardServiceAccount_failure_invalid_ttl() { UserDetails userDetails = getMockUser(true); String token = userDetails.getClientToken(); ServiceAccount serviceAccount = new ServiceAccount(); serviceAccount.setName("testacc02"); serviceAccount.setAutoRotate(true); serviceAccount.setOwner("testacc01"); String expectedResponse = "{\"errors\":[\"Invalid or no value has been provided for MAX_TTL\"]}"; ResponseEntity<String> responseEntityExpected = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(expectedResponse); Response response = getMockResponse(HttpStatus.OK, true, "{\"keys\":[\"testacc03\"]}"); when(reqProcessor.process("/ad/serviceaccount/onboardedlist","{}",token)).thenReturn(response); List<ADServiceAccount> allServiceAccounts = new ArrayList<>(); allServiceAccounts.add(generateADServiceAccount("testacc02")); ReflectionTestUtils.setField(serviceAccountsService, "ldapTemplate", ldapTemplate); when(ldapTemplate.search(Mockito.anyString(), Mockito.any(), Mockito.any(AttributesMapper.class))).thenReturn(allServiceAccounts); ResponseEntity<String> responseEntity = serviceAccountsService.onboardServiceAccount(token, serviceAccount, userDetails); assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); assertEquals(responseEntityExpected, responseEntity); }
@Test public void test_onboardServiceAccount_succss_autorotate_on_ttl_biggerthan_maxallowed() { UserDetails userDetails = getMockUser(true); String token = userDetails.getClientToken(); ServiceAccount serviceAccount = generateServiceAccount("testacc02","testacc01"); serviceAccount.setAutoRotate(true); serviceAccount.setTtl(1590897977L); serviceAccount.setMax_ttl(1590897977L); String expectedResponse = "{\"errors\":[\"Invalid value provided for Password Expiration Time. This can't be more than 31536000 for this Service Account\"]}"; ResponseEntity<String> responseEntityExpected = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(expectedResponse); Response response = getMockResponse(HttpStatus.OK, true, "{\"keys\":[\"testacc03\"]}"); when(reqProcessor.process("/ad/serviceaccount/onboardedlist","{}",token)).thenReturn(response); List<ADServiceAccount> allServiceAccounts = new ArrayList<>(); allServiceAccounts.add(generateADServiceAccount("testacc02")); ReflectionTestUtils.setField(serviceAccountsService, "ldapTemplate", ldapTemplate); when(ldapTemplate.search(Mockito.anyString(), Mockito.any(), Mockito.any(AttributesMapper.class))).thenReturn(allServiceAccounts); ResponseEntity<String> responseEntity = serviceAccountsService.onboardServiceAccount(token, serviceAccount, userDetails); assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); assertEquals(responseEntityExpected, responseEntity); }
@Test public void test_onboardServiceAccount_BadRequest_for_AccountRole() { UserDetails userDetails = getMockUser(true); String token = userDetails.getClientToken(); ServiceAccount serviceAccount = generateServiceAccount("testacc02","testacc01"); serviceAccount.setAutoRotate(true); Response response = getMockResponse(HttpStatus.OK, true, "{\"keys\":[\"testacc03\"]}"); when(reqProcessor.process("/ad/serviceaccount/onboardedlist","{}",token)).thenReturn(response); List<ADServiceAccount> allServiceAccounts = new ArrayList<>(); allServiceAccounts.add(generateADServiceAccount("testacc02")); ReflectionTestUtils.setField(serviceAccountsService, "ldapTemplate", ldapTemplate); when(ldapTemplate.search(Mockito.anyString(), Mockito.any(), Mockito.any(AttributesMapper.class))).thenReturn(allServiceAccounts); ServiceAccountTTL serviceAccountTTL = new ServiceAccountTTL(); serviceAccountTTL.setRole_name(serviceAccount.getName()); serviceAccountTTL.setService_account_name(serviceAccount.getName() + "@aaa.bbb.ccc.com") ; serviceAccountTTL.setTtl(serviceAccount.getTtl()); String svc_account_payload = getJSON(serviceAccountTTL); when(JSONUtil.getJSON(Mockito.any(ServiceAccountTTL.class))).thenReturn(svc_account_payload); Response onboardResponse = getMockResponse(HttpStatus.BAD_REQUEST, true, "{\"errors\":[\"Failed to create service account role.\"]}"); when(reqProcessor.process("/ad/serviceaccount/onboard", svc_account_payload, token)).thenReturn(onboardResponse); String expectedResponse = "{\"errors\":[\"Failed to onboard AD service account into TVault for password rotation.\"]}"; ResponseEntity<String> responseEntityExpected = ResponseEntity.status(HttpStatus.BAD_REQUEST).body(expectedResponse); ResponseEntity<String> responseEntity = serviceAccountsService.onboardServiceAccount(token, serviceAccount, userDetails); assertEquals(HttpStatus.BAD_REQUEST, responseEntity.getStatusCode()); assertEquals(responseEntityExpected, responseEntity); }