diff --git a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminAccountTest.java b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminAccountTest.java index 6e69f670..a25ba837 100644 --- a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminAccountTest.java +++ b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminAccountTest.java @@ -1,17 +1,9 @@ package uk.gov.hmcts.reform.pip.account.management.controllers; import com.fasterxml.jackson.databind.ObjectMapper; -import com.microsoft.graph.models.User; -import com.microsoft.graph.models.UserCollectionResponse; -import com.microsoft.graph.serviceclient.GraphServiceClient; -import com.microsoft.graph.users.UsersRequestBuilder; -import com.microsoft.kiota.ApiException; import io.zonky.test.db.AutoConfigureEmbeddedDatabase; -import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; -import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; -import org.mockito.Mockito; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; import org.springframework.boot.test.context.SpringBootTest; @@ -26,16 +18,12 @@ import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; import uk.gov.hmcts.reform.pip.account.management.Application; import uk.gov.hmcts.reform.pip.account.management.config.AzureConfigurationClientTestConfiguration; -import uk.gov.hmcts.reform.pip.account.management.model.AzureAccount; import uk.gov.hmcts.reform.pip.account.management.model.PiUser; import uk.gov.hmcts.reform.pip.account.management.model.SystemAdminAccount; -import java.util.ArrayList; -import java.util.List; +import java.util.UUID; import static org.junit.jupiter.api.Assertions.assertEquals; -import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; import static org.springframework.http.HttpStatus.BAD_REQUEST; import static org.springframework.http.HttpStatus.FORBIDDEN; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @@ -48,70 +36,36 @@ @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) @WithMockUser(username = "admin", authorities = {"APPROLE_api.request.admin"}) class SystemAdminAccountTest { + private static final String ROOT_URL = "/account"; - private static final String CREATE_SYSTEM_ADMIN_URL = ROOT_URL + "/add/system-admin"; - private static final String AZURE_PATH = "/azure/"; + private static final String CREATE_SYSTEM_ADMIN_URL = ROOT_URL + "/system-admin"; - private static final String ISSUER_ID = "1234-1234-1234-1234"; private static final String SYSTEM_ADMIN_ISSUER_ID = "87f907d2-eb28-42cc-b6e1-ae2b03f7bba2"; private static final String ISSUER_HEADER = "x-issuer-id"; - private static final String GIVEN_NAME = "Given Name"; - private static final String ID = "1234"; private static final String TEST_SYS_ADMIN_SURNAME = "testSysAdminSurname"; private static final String TEST_SYS_ADMIN_FIRSTNAME = "testSysAdminFirstname"; private static final String TEST_SYS_ADMIN_EMAIL = "testSysAdminEmail@justice.gov.uk"; private static final String FORBIDDEN_STATUS_CODE = "Status code does not match forbidden"; + private static final String SQL_ADD_ADMIN = "classpath:add-admin-users.sql"; private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); @Autowired private MockMvc mockMvc; - @Autowired - GraphServiceClient graphClient; - - @Autowired - UsersRequestBuilder usersRequestBuilder; - - - @Autowired - ApiException apiException; - @BeforeAll static void startup() { OBJECT_MAPPER.findAndRegisterModules(); } - @BeforeEach - void setup() { - User user = new User(); - user.setId(ID); - user.setGivenName(GIVEN_NAME); - - List azUsers = new ArrayList<>(); - azUsers.add(user); - - when(graphClient.users()).thenReturn(usersRequestBuilder); - when(usersRequestBuilder.post(any())).thenReturn(user); - - UserCollectionResponse userCollectionResponse = new UserCollectionResponse(); - userCollectionResponse.setValue(azUsers); - - when(usersRequestBuilder.get(any())).thenReturn(userCollectionResponse); - } - - @AfterEach - public void reset() { - Mockito.reset(graphClient, usersRequestBuilder); - } - @Test - @Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:add-admin-users.sql") - void testCreateSystemAdminAccount() throws Exception { + @Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = SQL_ADD_ADMIN) + void testUserCanCreateSystemAdminAccount() throws Exception { SystemAdminAccount systemAdmin = new SystemAdminAccount(); systemAdmin.setFirstName(TEST_SYS_ADMIN_FIRSTNAME); systemAdmin.setSurname(TEST_SYS_ADMIN_SURNAME); systemAdmin.setEmail(TEST_SYS_ADMIN_EMAIL); + systemAdmin.setProvenanceUserId(UUID.randomUUID().toString()); MockHttpServletRequestBuilder createRequest = MockMvcRequestBuilders @@ -135,12 +89,13 @@ void testCreateSystemAdminAccount() throws Exception { } @Test - @Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:add-admin-users.sql") + @Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = SQL_ADD_ADMIN) void testCreateSystemAdminAccountRequestExceeded() throws Exception { SystemAdminAccount systemAdmin1 = new SystemAdminAccount(); systemAdmin1.setFirstName("testSysAdminFirstname1"); systemAdmin1.setSurname("testSysAdminSurname1"); systemAdmin1.setEmail("testSysAdminEmai1l@justice.gov.uk"); + systemAdmin1.setProvenanceUserId(UUID.randomUUID().toString()); MockHttpServletRequestBuilder createRequest1 = MockMvcRequestBuilders @@ -156,6 +111,7 @@ void testCreateSystemAdminAccountRequestExceeded() throws Exception { systemAdmin2.setFirstName("testSysAdminFirstname2"); systemAdmin2.setSurname("testSysAdminSurname2"); systemAdmin2.setEmail("testSysAdminEmai12@justice.gov.uk"); + systemAdmin2.setProvenanceUserId(UUID.randomUUID().toString()); MockHttpServletRequestBuilder createRequest2 = MockMvcRequestBuilders @@ -173,12 +129,11 @@ void testCreateSystemAdminAccountRequestExceeded() throws Exception { } @Test - @Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:add-admin-users.sql") - void testGetAzureUserInfo() throws Exception { + @Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = SQL_ADD_ADMIN) + void testCreateSystemAdminReturnsBadRequest() throws Exception { SystemAdminAccount systemAdmin = new SystemAdminAccount(); systemAdmin.setFirstName(TEST_SYS_ADMIN_FIRSTNAME); systemAdmin.setSurname(TEST_SYS_ADMIN_SURNAME); - systemAdmin.setEmail(TEST_SYS_ADMIN_EMAIL); MockHttpServletRequestBuilder createRequest = MockMvcRequestBuilders @@ -188,41 +143,27 @@ void testGetAzureUserInfo() throws Exception { .contentType(MediaType.APPLICATION_JSON); MvcResult responseCreateSystemAdminUser = mockMvc.perform(createRequest) - .andExpect(status().isOk()).andReturn(); - - PiUser returnedUser = OBJECT_MAPPER.readValue( - responseCreateSystemAdminUser.getResponse().getContentAsString(), - PiUser.class - ); - - MockHttpServletRequestBuilder getRequest = MockMvcRequestBuilders - .get(ROOT_URL + AZURE_PATH + returnedUser.getProvenanceUserId()); - - MvcResult responseGetUser = - mockMvc.perform(getRequest).andExpect(status().isOk()).andReturn(); + .andExpect(status().isBadRequest()).andReturn(); - AzureAccount returnedAzureAccount = OBJECT_MAPPER.readValue( - responseGetUser.getResponse().getContentAsString(), - AzureAccount.class - ); - assertEquals(returnedUser.getEmail(), returnedAzureAccount.getEmail(), - "Should return the correct user" + assertEquals(BAD_REQUEST.value(), responseCreateSystemAdminUser.getResponse().getStatus(), + "Should return bad request" ); } @Test - @WithMockUser(username = "unauthroized_user", authorities = {"APPROLE_unknown.user"}) - void testUnauthorizedCreateSystemAdminAccount() throws Exception { + @Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = SQL_ADD_ADMIN) + void testNonSystemAdminIsForbiddenToCreateSystemAdminAccount() throws Exception { SystemAdminAccount systemAdmin = new SystemAdminAccount(); systemAdmin.setFirstName(TEST_SYS_ADMIN_FIRSTNAME); systemAdmin.setSurname(TEST_SYS_ADMIN_SURNAME); systemAdmin.setEmail(TEST_SYS_ADMIN_EMAIL); + systemAdmin.setProvenanceUserId(UUID.randomUUID().toString()); MockHttpServletRequestBuilder createRequest = MockMvcRequestBuilders .post(CREATE_SYSTEM_ADMIN_URL) .content(OBJECT_MAPPER.writeValueAsString(systemAdmin)) - .header(ISSUER_HEADER, ISSUER_ID) + .header(ISSUER_HEADER, "87f907d2-eb28-42cc-b6e1-ae2b03f7bba3") .contentType(MediaType.APPLICATION_JSON); MvcResult responseCreateSystemAdminUser = mockMvc.perform(createRequest) diff --git a/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminB2CAccountTest.java b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminB2CAccountTest.java new file mode 100644 index 00000000..c2ad4bf0 --- /dev/null +++ b/src/functionalTest/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminB2CAccountTest.java @@ -0,0 +1,235 @@ +package uk.gov.hmcts.reform.pip.account.management.controllers; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.microsoft.graph.models.User; +import com.microsoft.graph.models.UserCollectionResponse; +import com.microsoft.graph.serviceclient.GraphServiceClient; +import com.microsoft.graph.users.UsersRequestBuilder; +import com.microsoft.kiota.ApiException; +import io.zonky.test.db.AutoConfigureEmbeddedDatabase; +import org.junit.jupiter.api.AfterEach; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.mockito.Mockito; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc; +import org.springframework.boot.test.context.SpringBootTest; +import org.springframework.http.MediaType; +import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.test.annotation.DirtiesContext; +import org.springframework.test.context.ActiveProfiles; +import org.springframework.test.context.jdbc.Sql; +import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.MvcResult; +import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder; +import org.springframework.test.web.servlet.request.MockMvcRequestBuilders; +import uk.gov.hmcts.reform.pip.account.management.Application; +import uk.gov.hmcts.reform.pip.account.management.config.AzureConfigurationClientTestConfiguration; +import uk.gov.hmcts.reform.pip.account.management.model.AzureAccount; +import uk.gov.hmcts.reform.pip.account.management.model.PiUser; +import uk.gov.hmcts.reform.pip.account.management.model.SystemAdminAccount; + +import java.util.ArrayList; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.Mockito.when; +import static org.springframework.http.HttpStatus.BAD_REQUEST; +import static org.springframework.http.HttpStatus.FORBIDDEN; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; + +@SpringBootTest(classes = {AzureConfigurationClientTestConfiguration.class, Application.class}, + webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) +@AutoConfigureMockMvc +@ActiveProfiles(profiles = "functional") +@AutoConfigureEmbeddedDatabase(type = AutoConfigureEmbeddedDatabase.DatabaseType.POSTGRES) +@DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD) +@WithMockUser(username = "admin", authorities = {"APPROLE_api.request.admin"}) +class SystemAdminB2CAccountTest { + private static final String ROOT_URL = "/account"; + private static final String CREATE_SYSTEM_ADMIN_URL = ROOT_URL + "/add/system-admin"; + private static final String AZURE_PATH = "/azure/"; + + private static final String ISSUER_ID = "1234-1234-1234-1234"; + private static final String SYSTEM_ADMIN_ISSUER_ID = "87f907d2-eb28-42cc-b6e1-ae2b03f7bba2"; + private static final String ISSUER_HEADER = "x-issuer-id"; + private static final String GIVEN_NAME = "Given Name"; + private static final String ID = "1234"; + private static final String TEST_SYS_ADMIN_SURNAME = "testSysAdminSurname"; + private static final String TEST_SYS_ADMIN_FIRSTNAME = "testSysAdminFirstname"; + private static final String TEST_SYS_ADMIN_EMAIL = "testSysAdminEmail@justice.gov.uk"; + private static final String FORBIDDEN_STATUS_CODE = "Status code does not match forbidden"; + + private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); + + @Autowired + private MockMvc mockMvc; + + @Autowired + GraphServiceClient graphClient; + + @Autowired + UsersRequestBuilder usersRequestBuilder; + + + @Autowired + ApiException apiException; + + @BeforeAll + static void startup() { + OBJECT_MAPPER.findAndRegisterModules(); + } + + @BeforeEach + void setup() { + User user = new User(); + user.setId(ID); + user.setGivenName(GIVEN_NAME); + + List azUsers = new ArrayList<>(); + azUsers.add(user); + + when(graphClient.users()).thenReturn(usersRequestBuilder); + when(usersRequestBuilder.post(any())).thenReturn(user); + + UserCollectionResponse userCollectionResponse = new UserCollectionResponse(); + userCollectionResponse.setValue(azUsers); + + when(usersRequestBuilder.get(any())).thenReturn(userCollectionResponse); + } + + @AfterEach + public void reset() { + Mockito.reset(graphClient, usersRequestBuilder); + } + + @Test + @Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:add-admin-users.sql") + void testCreateSystemAdminAccount() throws Exception { + SystemAdminAccount systemAdmin = new SystemAdminAccount(); + systemAdmin.setFirstName(TEST_SYS_ADMIN_FIRSTNAME); + systemAdmin.setSurname(TEST_SYS_ADMIN_SURNAME); + systemAdmin.setEmail(TEST_SYS_ADMIN_EMAIL); + + MockHttpServletRequestBuilder createRequest = + MockMvcRequestBuilders + .post(CREATE_SYSTEM_ADMIN_URL) + .content(OBJECT_MAPPER.writeValueAsString(systemAdmin)) + .header(ISSUER_HEADER, SYSTEM_ADMIN_ISSUER_ID) + .contentType(MediaType.APPLICATION_JSON); + + MvcResult responseCreateSystemAdminUser = mockMvc.perform(createRequest) + .andExpect(status().isOk()).andReturn(); + + PiUser returnedUser = OBJECT_MAPPER.readValue( + responseCreateSystemAdminUser.getResponse().getContentAsString(), + PiUser.class + ); + + assertEquals( + systemAdmin.getEmail(), returnedUser.getEmail(), + "Failed to create user" + ); + } + + @Test + @Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:add-admin-users.sql") + void testCreateSystemAdminAccountRequestExceeded() throws Exception { + SystemAdminAccount systemAdmin1 = new SystemAdminAccount(); + systemAdmin1.setFirstName("testSysAdminFirstname1"); + systemAdmin1.setSurname("testSysAdminSurname1"); + systemAdmin1.setEmail("testSysAdminEmai1l@justice.gov.uk"); + + MockHttpServletRequestBuilder createRequest1 = + MockMvcRequestBuilders + .post(CREATE_SYSTEM_ADMIN_URL) + .content(OBJECT_MAPPER.writeValueAsString(systemAdmin1)) + .header(ISSUER_HEADER, SYSTEM_ADMIN_ISSUER_ID) + .contentType(MediaType.APPLICATION_JSON); + + mockMvc.perform(createRequest1) + .andExpect(status().isOk()); + + SystemAdminAccount systemAdmin2 = new SystemAdminAccount(); + systemAdmin2.setFirstName("testSysAdminFirstname2"); + systemAdmin2.setSurname("testSysAdminSurname2"); + systemAdmin2.setEmail("testSysAdminEmai12@justice.gov.uk"); + + MockHttpServletRequestBuilder createRequest2 = + MockMvcRequestBuilders + .post(CREATE_SYSTEM_ADMIN_URL) + .content(OBJECT_MAPPER.writeValueAsString(systemAdmin2)) + .header(ISSUER_HEADER, SYSTEM_ADMIN_ISSUER_ID) + .contentType(MediaType.APPLICATION_JSON); + + MvcResult responseCreateSystemAdminUser = mockMvc.perform(createRequest2) + .andExpect(status().isBadRequest()).andReturn(); + + assertEquals(BAD_REQUEST.value(), responseCreateSystemAdminUser.getResponse().getStatus(), + "Number of system admin accounts exceeded the max limit" + ); + } + + @Test + @Sql(executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD, scripts = "classpath:add-admin-users.sql") + void testGetAzureUserInfo() throws Exception { + SystemAdminAccount systemAdmin = new SystemAdminAccount(); + systemAdmin.setFirstName(TEST_SYS_ADMIN_FIRSTNAME); + systemAdmin.setSurname(TEST_SYS_ADMIN_SURNAME); + systemAdmin.setEmail(TEST_SYS_ADMIN_EMAIL); + + MockHttpServletRequestBuilder createRequest = + MockMvcRequestBuilders + .post(CREATE_SYSTEM_ADMIN_URL) + .content(OBJECT_MAPPER.writeValueAsString(systemAdmin)) + .header(ISSUER_HEADER, SYSTEM_ADMIN_ISSUER_ID) + .contentType(MediaType.APPLICATION_JSON); + + MvcResult responseCreateSystemAdminUser = mockMvc.perform(createRequest) + .andExpect(status().isOk()).andReturn(); + + PiUser returnedUser = OBJECT_MAPPER.readValue( + responseCreateSystemAdminUser.getResponse().getContentAsString(), + PiUser.class + ); + + MockHttpServletRequestBuilder getRequest = MockMvcRequestBuilders + .get(ROOT_URL + AZURE_PATH + returnedUser.getProvenanceUserId()); + + MvcResult responseGetUser = + mockMvc.perform(getRequest).andExpect(status().isOk()).andReturn(); + + AzureAccount returnedAzureAccount = OBJECT_MAPPER.readValue( + responseGetUser.getResponse().getContentAsString(), + AzureAccount.class + ); + assertEquals(returnedUser.getEmail(), returnedAzureAccount.getEmail(), + "Should return the correct user" + ); + } + + @Test + @WithMockUser(username = "unauthroized_user", authorities = {"APPROLE_unknown.user"}) + void testUnauthorizedCreateSystemAdminAccount() throws Exception { + SystemAdminAccount systemAdmin = new SystemAdminAccount(); + systemAdmin.setFirstName(TEST_SYS_ADMIN_FIRSTNAME); + systemAdmin.setSurname(TEST_SYS_ADMIN_SURNAME); + systemAdmin.setEmail(TEST_SYS_ADMIN_EMAIL); + + MockHttpServletRequestBuilder createRequest = + MockMvcRequestBuilders + .post(CREATE_SYSTEM_ADMIN_URL) + .content(OBJECT_MAPPER.writeValueAsString(systemAdmin)) + .header(ISSUER_HEADER, ISSUER_ID) + .contentType(MediaType.APPLICATION_JSON); + + MvcResult responseCreateSystemAdminUser = mockMvc.perform(createRequest) + .andExpect(status().isForbidden()).andReturn(); + + assertEquals(FORBIDDEN.value(), responseCreateSystemAdminUser.getResponse().getStatus(), + FORBIDDEN_STATUS_CODE + ); + } +} diff --git a/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminAccountController.java b/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminAccountController.java index 6b6ad31d..f530d65c 100644 --- a/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminAccountController.java +++ b/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminAccountController.java @@ -5,6 +5,7 @@ import io.swagger.v3.oas.annotations.tags.Tag; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; +import org.springframework.security.access.prepost.PreAuthorize; import org.springframework.validation.annotation.Validated; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RequestBody; @@ -19,8 +20,6 @@ @RestController @Tag(name = "Account Management - API for managing system admin accounts") @RequestMapping("/account") -@ApiResponse(responseCode = "401", description = "Invalid access credential") -@ApiResponse(responseCode = "403", description = "User has not been authorized") @Validated @IsAdmin @SecurityRequirement(name = "bearerAuth") @@ -38,18 +37,20 @@ public SystemAdminAccountController(SystemAdminAccountService systemAdminAccount } /** - * POST endpoint that deals with creating a new System Admin Account (including PI and Azure) - * This will also trigger any welcome emails. + * Create a system admin account for SSO user on the user table. * - * @param issuerId The id of the user creating the accounts. + * @param issuerId The ID of the user creating the accounts. * @param account The account to add. * @return The PiUser that's been added, or an ErroredPiUser if it failed to add. */ @ApiResponse(responseCode = OK_CODE, description = PI_USER) @ApiResponse(responseCode = BAD_REQUEST_CODE, description = "{ErroredSystemAdminAccount}") - @PostMapping("/add/system-admin") - public ResponseEntity createSystemAdminAccount(//NOSONAR - @RequestHeader(ISSUER_ID) String issuerId, @RequestBody SystemAdminAccount account) { - return ResponseEntity.ok(systemAdminAccountService.addSystemAdminAccount(account, issuerId)); + @ApiResponse(responseCode = "401", description = "Invalid access credential") + @ApiResponse(responseCode = "403", description = "User has not been authorized") + @PostMapping("/system-admin") + @PreAuthorize("@authorisationService.userCanCreateSystemAdmin(#issuerId)") + public ResponseEntity createSystemAdminAccount(@RequestHeader(ISSUER_ID) String issuerId, + @RequestBody SystemAdminAccount account) { + return ResponseEntity.ok(systemAdminAccountService.addSystemAdminAccount(account)); } } diff --git a/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminB2CAccountController.java b/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminB2CAccountController.java new file mode 100644 index 00000000..5af1b895 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminB2CAccountController.java @@ -0,0 +1,55 @@ +package uk.gov.hmcts.reform.pip.account.management.controllers; + +import io.swagger.v3.oas.annotations.responses.ApiResponse; +import io.swagger.v3.oas.annotations.security.SecurityRequirement; +import io.swagger.v3.oas.annotations.tags.Tag; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.PostMapping; +import org.springframework.web.bind.annotation.RequestBody; +import org.springframework.web.bind.annotation.RequestHeader; +import org.springframework.web.bind.annotation.RequestMapping; +import org.springframework.web.bind.annotation.RestController; +import uk.gov.hmcts.reform.pip.account.management.model.PiUser; +import uk.gov.hmcts.reform.pip.account.management.model.SystemAdminAccount; +import uk.gov.hmcts.reform.pip.account.management.service.SystemAdminB2CAccountService; +import uk.gov.hmcts.reform.pip.model.authentication.roles.IsAdmin; + +@RestController +@Tag(name = "Account Management - API for managing B2C system admin accounts") +@RequestMapping("/account") +@ApiResponse(responseCode = "401", description = "Invalid access credential") +@ApiResponse(responseCode = "403", description = "User has not been authorized") +@Validated +@IsAdmin +@SecurityRequirement(name = "bearerAuth") +public class SystemAdminB2CAccountController { + private static final String ISSUER_ID = "x-issuer-id"; + private static final String OK_CODE = "200"; + private static final String BAD_REQUEST_CODE = "400"; + private static final String PI_USER = "{piUser}"; + + private final SystemAdminB2CAccountService systemAdminB2CAccountService; + + @Autowired + public SystemAdminB2CAccountController(SystemAdminB2CAccountService systemAdminB2CAccountService) { + this.systemAdminB2CAccountService = systemAdminB2CAccountService; + } + + /** + * POST endpoint that deals with creating a new System Admin Account (including PI and Azure) + * This will also trigger any welcome emails. + * + * @param issuerId The id of the user creating the accounts. + * @param account The account to add. + * @return The PiUser that's been added, or an ErroredPiUser if it failed to add. + */ + @ApiResponse(responseCode = OK_CODE, description = PI_USER) + @ApiResponse(responseCode = BAD_REQUEST_CODE, description = "{ErroredSystemAdminAccount}") + @PostMapping("/add/system-admin") + public ResponseEntity createSystemAdminAccount(//NOSONAR + @RequestHeader(ISSUER_ID) String issuerId, @RequestBody SystemAdminAccount account) { + return ResponseEntity.ok(systemAdminB2CAccountService.addSystemAdminAccount(account, issuerId)); + } +} diff --git a/src/main/java/uk/gov/hmcts/reform/pip/account/management/model/SystemAdminAccount.java b/src/main/java/uk/gov/hmcts/reform/pip/account/management/model/SystemAdminAccount.java index 9ba8477e..9c412cf9 100644 --- a/src/main/java/uk/gov/hmcts/reform/pip/account/management/model/SystemAdminAccount.java +++ b/src/main/java/uk/gov/hmcts/reform/pip/account/management/model/SystemAdminAccount.java @@ -2,6 +2,7 @@ import jakarta.validation.constraints.NotEmpty; import jakarta.validation.constraints.NotNull; +import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -14,6 +15,7 @@ /** * Model which represents a system admin account request. */ +@AllArgsConstructor @NoArgsConstructor @Getter @Setter @@ -31,6 +33,8 @@ public class SystemAdminAccount { @NotNull private String surname; + private String provenanceUserId; + public SystemAdminAccount(String email, String firstName, String surname) { this.firstName = firstName; this.surname = surname; @@ -49,7 +53,7 @@ public AzureAccount convertToAzureAccount() { public PiUser convertToPiUser(String provenanceUserId) { LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("UTC")); PiUser piUser = new PiUser(); - piUser.setEmail(this.getEmail()); + piUser.setEmail(email); piUser.setRoles(Roles.SYSTEM_ADMIN); piUser.setUserProvenance(UserProvenances.PI_AAD); piUser.setProvenanceUserId(provenanceUserId); @@ -59,4 +63,16 @@ public PiUser convertToPiUser(String provenanceUserId) { return piUser; } + public PiUser convertToPiUser() { + LocalDateTime localDateTime = LocalDateTime.now(ZoneId.of("UTC")); + PiUser piUser = new PiUser(); + piUser.setEmail(email); + piUser.setRoles(Roles.SYSTEM_ADMIN); + piUser.setUserProvenance(UserProvenances.SSO); + piUser.setProvenanceUserId(provenanceUserId); + piUser.setLastVerifiedDate(localDateTime); + piUser.setLastSignedInDate(localDateTime); + piUser.setCreatedDate(localDateTime); + return piUser; + } } diff --git a/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuthorisationService.java b/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuthorisationService.java index b4ffa413..c598a457 100644 --- a/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuthorisationService.java +++ b/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/AuthorisationService.java @@ -69,6 +69,15 @@ public boolean userCanUpdateAccount(UUID userId, UUID adminUserId) { return isAuthorised; } + public boolean userCanCreateSystemAdmin(UUID issuerId) { + Roles adminUserRole = getUserRole(issuerId); + if (Roles.SYSTEM_ADMIN.equals(adminUserRole)) { + return true; + } + log.error(writeLog(String.format("User with ID %s is forbidden to create system admin user", issuerId))); + return false; + } + private boolean isAuthorisedRole(UUID userId, UUID adminUserId) { if (adminUserId == null) { return false; diff --git a/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/SystemAdminAccountService.java b/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/SystemAdminAccountService.java index 123ea2ce..1faf763f 100644 --- a/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/SystemAdminAccountService.java +++ b/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/SystemAdminAccountService.java @@ -1,6 +1,5 @@ package uk.gov.hmcts.reform.pip.account.management.service; -import com.microsoft.graph.models.User; import jakarta.validation.ConstraintViolation; import jakarta.validation.Validator; import lombok.extern.slf4j.Slf4j; @@ -8,132 +7,65 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import uk.gov.hmcts.reform.pip.account.management.database.UserRepository; -import uk.gov.hmcts.reform.pip.account.management.errorhandling.exceptions.AzureCustomException; import uk.gov.hmcts.reform.pip.account.management.errorhandling.exceptions.SystemAdminAccountException; import uk.gov.hmcts.reform.pip.account.management.model.PiUser; import uk.gov.hmcts.reform.pip.account.management.model.SystemAdminAccount; import uk.gov.hmcts.reform.pip.account.management.model.errored.ErroredSystemAdminAccount; import uk.gov.hmcts.reform.pip.model.account.Roles; import uk.gov.hmcts.reform.pip.model.account.UserProvenances; -import uk.gov.hmcts.reform.pip.model.system.admin.ActionResult; -import uk.gov.hmcts.reform.pip.model.system.admin.CreateSystemAdminAction; import java.util.List; -import java.util.Optional; import java.util.Set; -import java.util.UUID; - -import static uk.gov.hmcts.reform.pip.model.LogBuilder.writeLog; /** - * Service class which deals with the creation of the System Admin accounts. A seperate class has been created due to - * the extra constraints and complexities of logging System Admin accounts. + * Service class which deals with the creation of the System Admin accounts on the user table. */ @Service @Slf4j public class SystemAdminAccountService { - - private final Validator validator; - private final AzureUserService azureUserService; private final UserRepository userRepository; - private final PublicationService publicationService; - private final AzureAccountService azureAccountService; private final Integer maxSystemAdminValue; @Autowired - public SystemAdminAccountService(Validator validator, AzureUserService azureUserService, - UserRepository userRepository, PublicationService publicationService, - @Value("${admin.max-system-admin}")Integer maxSystemAdminValue, - AzureAccountService azureAccountService) { + public SystemAdminAccountService(Validator validator, UserRepository userRepository, + @Value("${admin.max-system-admin}")Integer maxSystemAdminValue) { this.validator = validator; - this.azureUserService = azureUserService; this.userRepository = userRepository; - this.publicationService = publicationService; this.maxSystemAdminValue = maxSystemAdminValue; - this.azureAccountService = azureAccountService; } /** * This method deals with the creation of a system admin account. * @param account The system admin account to be created. - * @param issuerId The ID of the user creating the account. * @return The PiUser of the created system admin account. */ - public PiUser addSystemAdminAccount(SystemAdminAccount account, String issuerId) { + public PiUser addSystemAdminAccount(SystemAdminAccount account) { + validateSystemAdminAccount(account); + return userRepository.save(account.convertToPiUser()); - String displayName = ""; - String provenanceUserId = verifyAdminUser(issuerId); - if (!provenanceUserId.isEmpty()) { - displayName = azureAccountService.retrieveAzureAccount(provenanceUserId).getDisplayName(); - } - - validateSystemAdminAccount(account, issuerId, displayName); - try { - User user = azureUserService.createUser(account.convertToAzureAccount(), false); - PiUser createdUser = userRepository.save(account.convertToPiUser(user.getId())); - handleNewSystemAdminAccountAction(account, issuerId, ActionResult.SUCCEEDED, displayName); - - publicationService.sendNotificationEmail( - account.getEmail(), - account.getFirstName(), - account.getSurname() - ); - return createdUser; - } catch (AzureCustomException e) { - ErroredSystemAdminAccount erroredSystemAdminAccount = new ErroredSystemAdminAccount(account); - erroredSystemAdminAccount.setErrorMessages(List.of(e.getLocalizedMessage())); - handleNewSystemAdminAccountAction(account, issuerId, ActionResult.FAILED, displayName); - throw new SystemAdminAccountException(erroredSystemAdminAccount); - } - } - - /** - * This method handles the logging and publishing that a new system admin account has been created. - * @param systemAdminAccount The system admin account that has been created - * @param adminId The ID of the admin user who is creating the account. - * @param name The name of the admin user who is creating the account - */ - public void handleNewSystemAdminAccountAction(SystemAdminAccount systemAdminAccount, String adminId, - ActionResult result, String name) { - log.info(writeLog(UUID.fromString(adminId), - "has attempted to create a System Admin account, which has: " + result.toString())); - - List existingAdminEmails = userRepository.findByRoles(Roles.SYSTEM_ADMIN) - .stream().map(PiUser::getEmail).toList(); - - CreateSystemAdminAction createSystemAdminAction = new CreateSystemAdminAction(); - createSystemAdminAction.setAccountEmail(systemAdminAccount.getEmail()); - createSystemAdminAction.setEmailList(existingAdminEmails); - createSystemAdminAction.setRequesterName(name); - createSystemAdminAction.setActionResult(result); - - publicationService.sendSystemAdminAccountAction(createSystemAdminAction); } /** * A helper method which specifically handles validation failures on the system admin account. * @param account The system admin account to validate. - * @param issuerId The ID of the admin user that is issuing the account. - * @param name The name of the admin user requesting the account. */ - private void validateSystemAdminAccount(SystemAdminAccount account, String issuerId, String name) { - Set> constraintViolationSet = validator.validate(account); + private void validateSystemAdminAccount(SystemAdminAccount account) { + Set> constraintViolations = validator.validate(account); - if (!constraintViolationSet.isEmpty()) { + if (!constraintViolations.isEmpty()) { ErroredSystemAdminAccount erroredSystemAdminAccount = new ErroredSystemAdminAccount(account); - erroredSystemAdminAccount.setErrorMessages(constraintViolationSet - .stream().map(constraint -> constraint.getPropertyPath() - + ": " + constraint.getMessage()).toList()); - - handleNewSystemAdminAccountAction(account, issuerId, ActionResult.FAILED, name); + erroredSystemAdminAccount.setErrorMessages( + constraintViolations.stream() + .map(constraint -> constraint.getPropertyPath() + ": " + constraint.getMessage()) + .toList() + ); throw new SystemAdminAccountException(erroredSystemAdminAccount); } - if (userRepository.findByEmailAndUserProvenance(account.getEmail(), UserProvenances.PI_AAD).isPresent()) { + if (userRepository.findByEmailAndUserProvenance(account.getEmail(), UserProvenances.SSO).isPresent()) { ErroredSystemAdminAccount erroredSystemAdminAccount = new ErroredSystemAdminAccount(account); erroredSystemAdminAccount.setDuplicate(true); - handleNewSystemAdminAccountAction(account, issuerId, ActionResult.FAILED, name); throw new SystemAdminAccountException(erroredSystemAdminAccount); } @@ -141,22 +73,7 @@ private void validateSystemAdminAccount(SystemAdminAccount account, String issue if (systemAdminUsers.size() >= maxSystemAdminValue) { ErroredSystemAdminAccount erroredSystemAdminAccount = new ErroredSystemAdminAccount(account); erroredSystemAdminAccount.setAboveMaxSystemAdmin(true); - handleNewSystemAdminAccountAction(account, issuerId, ActionResult.ATTEMPTED, name); throw new SystemAdminAccountException(erroredSystemAdminAccount); } } - - /** - * Method to find whether user is SYSTEM_ADMIN or not. - * @param issuerId The ID of the admin user - * @return Boolean user is SYSTEM_ADMIN or not - */ - private String verifyAdminUser(String issuerId) { - Optional adminUser = userRepository.findByUserId(UUID.fromString(issuerId)); - if (adminUser.isPresent() && adminUser.get().getRoles().equals(Roles.SYSTEM_ADMIN)) { - return adminUser.get().getProvenanceUserId(); - } - - return ""; - } } diff --git a/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/SystemAdminB2CAccountService.java b/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/SystemAdminB2CAccountService.java new file mode 100644 index 00000000..b537c511 --- /dev/null +++ b/src/main/java/uk/gov/hmcts/reform/pip/account/management/service/SystemAdminB2CAccountService.java @@ -0,0 +1,162 @@ +package uk.gov.hmcts.reform.pip.account.management.service; + +import com.microsoft.graph.models.User; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Validator; +import lombok.extern.slf4j.Slf4j; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Service; +import uk.gov.hmcts.reform.pip.account.management.database.UserRepository; +import uk.gov.hmcts.reform.pip.account.management.errorhandling.exceptions.AzureCustomException; +import uk.gov.hmcts.reform.pip.account.management.errorhandling.exceptions.SystemAdminAccountException; +import uk.gov.hmcts.reform.pip.account.management.model.PiUser; +import uk.gov.hmcts.reform.pip.account.management.model.SystemAdminAccount; +import uk.gov.hmcts.reform.pip.account.management.model.errored.ErroredSystemAdminAccount; +import uk.gov.hmcts.reform.pip.model.account.Roles; +import uk.gov.hmcts.reform.pip.model.account.UserProvenances; +import uk.gov.hmcts.reform.pip.model.system.admin.ActionResult; +import uk.gov.hmcts.reform.pip.model.system.admin.CreateSystemAdminAction; + +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; + +import static uk.gov.hmcts.reform.pip.model.LogBuilder.writeLog; + +/** + * Service class which deals with the creation of the System Admin accounts. A seperate class has been created due to + * the extra constraints and complexities of logging System Admin accounts. + */ +@Service +@Slf4j +public class SystemAdminB2CAccountService { + + + private final Validator validator; + private final AzureUserService azureUserService; + private final UserRepository userRepository; + private final PublicationService publicationService; + private final AzureAccountService azureAccountService; + private final Integer maxSystemAdminValue; + + @Autowired + public SystemAdminB2CAccountService(Validator validator, AzureUserService azureUserService, + UserRepository userRepository, PublicationService publicationService, + @Value("${admin.max-system-admin}")Integer maxSystemAdminValue, + AzureAccountService azureAccountService) { + this.validator = validator; + this.azureUserService = azureUserService; + this.userRepository = userRepository; + this.publicationService = publicationService; + this.maxSystemAdminValue = maxSystemAdminValue; + this.azureAccountService = azureAccountService; + } + + /** + * This method deals with the creation of a system admin account. + * @param account The system admin account to be created. + * @param issuerId The ID of the user creating the account. + * @return The PiUser of the created system admin account. + */ + public PiUser addSystemAdminAccount(SystemAdminAccount account, String issuerId) { + + String displayName = ""; + String provenanceUserId = verifyAdminUser(issuerId); + if (!provenanceUserId.isEmpty()) { + displayName = azureAccountService.retrieveAzureAccount(provenanceUserId).getDisplayName(); + } + + validateSystemAdminAccount(account, issuerId, displayName); + try { + User user = azureUserService.createUser(account.convertToAzureAccount(), false); + PiUser createdUser = userRepository.save(account.convertToPiUser(user.getId())); + handleNewSystemAdminAccountAction(account, issuerId, ActionResult.SUCCEEDED, displayName); + + publicationService.sendNotificationEmail( + account.getEmail(), + account.getFirstName(), + account.getSurname() + ); + return createdUser; + } catch (AzureCustomException e) { + ErroredSystemAdminAccount erroredSystemAdminAccount = new ErroredSystemAdminAccount(account); + erroredSystemAdminAccount.setErrorMessages(List.of(e.getLocalizedMessage())); + handleNewSystemAdminAccountAction(account, issuerId, ActionResult.FAILED, displayName); + throw new SystemAdminAccountException(erroredSystemAdminAccount); + } + } + + /** + * This method handles the logging and publishing that a new system admin account has been created. + * @param systemAdminAccount The system admin account that has been created + * @param adminId The ID of the admin user who is creating the account. + * @param name The name of the admin user who is creating the account + */ + public void handleNewSystemAdminAccountAction(SystemAdminAccount systemAdminAccount, String adminId, + ActionResult result, String name) { + log.info(writeLog(UUID.fromString(adminId), + "has attempted to create a System Admin account, which has: " + result.toString())); + + List existingAdminEmails = userRepository.findByRoles(Roles.SYSTEM_ADMIN) + .stream().map(PiUser::getEmail).toList(); + + CreateSystemAdminAction createSystemAdminAction = new CreateSystemAdminAction(); + createSystemAdminAction.setAccountEmail(systemAdminAccount.getEmail()); + createSystemAdminAction.setEmailList(existingAdminEmails); + createSystemAdminAction.setRequesterName(name); + createSystemAdminAction.setActionResult(result); + + publicationService.sendSystemAdminAccountAction(createSystemAdminAction); + } + + /** + * A helper method which specifically handles validation failures on the system admin account. + * @param account The system admin account to validate. + * @param issuerId The ID of the admin user that is issuing the account. + * @param name The name of the admin user requesting the account. + */ + private void validateSystemAdminAccount(SystemAdminAccount account, String issuerId, String name) { + Set> constraintViolationSet = validator.validate(account); + + if (!constraintViolationSet.isEmpty()) { + ErroredSystemAdminAccount erroredSystemAdminAccount = new ErroredSystemAdminAccount(account); + erroredSystemAdminAccount.setErrorMessages(constraintViolationSet + .stream().map(constraint -> constraint.getPropertyPath() + + ": " + constraint.getMessage()).toList()); + + handleNewSystemAdminAccountAction(account, issuerId, ActionResult.FAILED, name); + throw new SystemAdminAccountException(erroredSystemAdminAccount); + } + + if (userRepository.findByEmailAndUserProvenance(account.getEmail(), UserProvenances.PI_AAD).isPresent()) { + ErroredSystemAdminAccount erroredSystemAdminAccount = new ErroredSystemAdminAccount(account); + erroredSystemAdminAccount.setDuplicate(true); + handleNewSystemAdminAccountAction(account, issuerId, ActionResult.FAILED, name); + throw new SystemAdminAccountException(erroredSystemAdminAccount); + } + + List systemAdminUsers = userRepository.findByRoles(Roles.SYSTEM_ADMIN); + if (systemAdminUsers.size() >= maxSystemAdminValue) { + ErroredSystemAdminAccount erroredSystemAdminAccount = new ErroredSystemAdminAccount(account); + erroredSystemAdminAccount.setAboveMaxSystemAdmin(true); + handleNewSystemAdminAccountAction(account, issuerId, ActionResult.ATTEMPTED, name); + throw new SystemAdminAccountException(erroredSystemAdminAccount); + } + } + + /** + * Method to find whether user is SYSTEM_ADMIN or not. + * @param issuerId The ID of the admin user + * @return Boolean user is SYSTEM_ADMIN or not + */ + private String verifyAdminUser(String issuerId) { + Optional adminUser = userRepository.findByUserId(UUID.fromString(issuerId)); + if (adminUser.isPresent() && adminUser.get().getRoles().equals(Roles.SYSTEM_ADMIN)) { + return adminUser.get().getProvenanceUserId(); + } + + return ""; + } +} diff --git a/src/test/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminAccountControllerTest.java b/src/test/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminAccountControllerTest.java index 04979bf8..661aefb5 100644 --- a/src/test/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminAccountControllerTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminAccountControllerTest.java @@ -19,7 +19,9 @@ @ExtendWith(MockitoExtension.class) class SystemAdminAccountControllerTest { private static final String TEST_EMAIL = "test@user.com"; + private static final String TEST_PROVENANCE_ID = "1234"; private static final String STATUS_CODE_MATCH = "Status code responses should match"; + private static final String RESPONSE_BODY_MATCH = "Expected user does not match"; @Mock private SystemAdminAccountService systemAdminAccountService; @@ -29,22 +31,22 @@ class SystemAdminAccountControllerTest { @Test void testCreateSystemAdminAccount() { - PiUser testUser = new PiUser(); - testUser.setEmail(TEST_EMAIL); - testUser.setRoles(Roles.SYSTEM_ADMIN); - testUser.setUserProvenance(UserProvenances.PI_AAD); + PiUser expectedUser = new PiUser(); + expectedUser.setEmail(TEST_EMAIL); + expectedUser.setRoles(Roles.SYSTEM_ADMIN); + expectedUser.setUserProvenance(UserProvenances.SSO); + expectedUser.setProvenanceUserId(TEST_PROVENANCE_ID); - SystemAdminAccount testAccount = new SystemAdminAccount(TEST_EMAIL, - "Test", "User"); + SystemAdminAccount testAccount = new SystemAdminAccount(TEST_EMAIL, "Test", "User", TEST_PROVENANCE_ID); String testIssuerId = "1234"; - when(systemAdminAccountService.addSystemAdminAccount(testAccount, testIssuerId)).thenReturn(testUser); + when(systemAdminAccountService.addSystemAdminAccount(testAccount)).thenReturn(expectedUser); ResponseEntity response = systemAdminAccountController.createSystemAdminAccount( testIssuerId, testAccount ); assertEquals(HttpStatus.OK, response.getStatusCode(), STATUS_CODE_MATCH); - assertEquals(testUser, response.getBody(), "Should return the created piUser"); + assertEquals(expectedUser, response.getBody(), RESPONSE_BODY_MATCH); } } diff --git a/src/test/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminB2CAccountControllerTest.java b/src/test/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminB2CAccountControllerTest.java new file mode 100644 index 00000000..d0f2c2d0 --- /dev/null +++ b/src/test/java/uk/gov/hmcts/reform/pip/account/management/controllers/SystemAdminB2CAccountControllerTest.java @@ -0,0 +1,50 @@ +package uk.gov.hmcts.reform.pip.account.management.controllers; + +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import uk.gov.hmcts.reform.pip.account.management.model.PiUser; +import uk.gov.hmcts.reform.pip.account.management.model.SystemAdminAccount; +import uk.gov.hmcts.reform.pip.account.management.service.SystemAdminB2CAccountService; +import uk.gov.hmcts.reform.pip.model.account.Roles; +import uk.gov.hmcts.reform.pip.model.account.UserProvenances; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class SystemAdminB2CAccountControllerTest { + private static final String TEST_EMAIL = "test@user.com"; + private static final String STATUS_CODE_MATCH = "Status code responses should match"; + + @Mock + private SystemAdminB2CAccountService systemAdminAccountService; + + @InjectMocks + private SystemAdminB2CAccountController systemAdminAccountController; + + @Test + void testCreateSystemAdminAccount() { + PiUser testUser = new PiUser(); + testUser.setEmail(TEST_EMAIL); + testUser.setRoles(Roles.SYSTEM_ADMIN); + testUser.setUserProvenance(UserProvenances.PI_AAD); + + SystemAdminAccount testAccount = new SystemAdminAccount(TEST_EMAIL, + "Test", "User"); + + String testIssuerId = "1234"; + when(systemAdminAccountService.addSystemAdminAccount(testAccount, testIssuerId)).thenReturn(testUser); + + ResponseEntity response = systemAdminAccountController.createSystemAdminAccount( + testIssuerId, testAccount + ); + + assertEquals(HttpStatus.OK, response.getStatusCode(), STATUS_CODE_MATCH); + assertEquals(testUser, response.getBody(), "Should return the created piUser"); + } +} diff --git a/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/AuthorisationServiceTest.java b/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/AuthorisationServiceTest.java index 28d6ae9d..6832dc9e 100644 --- a/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/AuthorisationServiceTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/AuthorisationServiceTest.java @@ -20,6 +20,7 @@ import java.util.UUID; import static org.assertj.core.api.Assertions.assertThatThrownBy; +import static org.junit.jupiter.params.provider.EnumSource.Mode.INCLUDE; import static org.mockito.Mockito.lenient; import static org.mockito.Mockito.verifyNoInteractions; import static org.mockito.Mockito.verifyNoMoreInteractions; @@ -35,6 +36,8 @@ class AuthorisationServiceTest { private static final String UPDATE_ERROR_LOG = "User with ID %s is forbidden to update user with ID %s"; private static final String UPDATE_OWN_ACCOUNT_ERROR_LOG = "User with ID %s is forbidden to update their own account"; + private static final String CREATE_SYSTEM_ADMIN_ERROR_LOG = + "User with ID %s is forbidden to create system admin user"; private static final String CAN_DELETE_ACCOUNT_MESSAGE = "User should be able to delete account"; private static final String CANNOT_DELETE_ACCOUNT_MESSAGE = "User should not be able to delete account"; @@ -626,4 +629,51 @@ void testExceptionThrowIfAdminUserNotFound() { .isInstanceOf(NotFoundException.class) .hasMessage(String.format("User with supplied user id: %s could not be found", ADMIN_USER_ID)); } + + @Test + void testSystemAdminCanCreateSystemAdmin() { + adminUser.setRoles(Roles.SYSTEM_ADMIN); + when(userRepository.findByUserId(ADMIN_USER_ID)).thenReturn(Optional.of(adminUser)); + + try (LogCaptor logCaptor = LogCaptor.forClass(AuthorisationService.class)) { + SoftAssertions softly = new SoftAssertions(); + + softly.assertThat(authorisationService.userCanCreateSystemAdmin(ADMIN_USER_ID)) + .as(CAN_CREATE_ACCOUNT_MESSAGE) + .isTrue(); + + softly.assertThat(logCaptor.getErrorLogs()) + .as(LOG_MATCHED_MESSAGE) + .isEmpty(); + + softly.assertAll(); + } + } + + @ParameterizedTest + @EnumSource(value = Roles.class, mode = INCLUDE, names = { + "INTERNAL_SUPER_ADMIN_CTSC", "INTERNAL_SUPER_ADMIN_LOCAL", "INTERNAL_ADMIN_CTSC", "INTERNAL_ADMIN_LOCAL" + }) + void testNonSystemAdminCannotCreateSystemAdmin(Roles role) { + adminUser.setRoles(role); + when(userRepository.findByUserId(ADMIN_USER_ID)).thenReturn(Optional.of(adminUser)); + + try (LogCaptor logCaptor = LogCaptor.forClass(AuthorisationService.class)) { + SoftAssertions softly = new SoftAssertions(); + + softly.assertThat(authorisationService.userCanCreateSystemAdmin(ADMIN_USER_ID)) + .as(CANNOT_CREATE_ACCOUNT_MESSAGE) + .isFalse(); + + softly.assertThat(logCaptor.getErrorLogs()) + .as(LOG_NOT_EMPTY_MESSAGE) + .hasSize(1); + + softly.assertThat(logCaptor.getErrorLogs().get(0)) + .as(LOG_MATCHED_MESSAGE) + .contains(String.format(CREATE_SYSTEM_ADMIN_ERROR_LOG, ADMIN_USER_ID)); + + softly.assertAll(); + } + } } diff --git a/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/SystemAdminAccountServiceTest.java b/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/SystemAdminAccountServiceTest.java index e44c4f34..4b9fd02c 100644 --- a/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/SystemAdminAccountServiceTest.java +++ b/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/SystemAdminAccountServiceTest.java @@ -1,26 +1,21 @@ package uk.gov.hmcts.reform.pip.account.management.service; -import com.microsoft.graph.models.User; import jakarta.validation.ConstraintViolation; import jakarta.validation.Path; import jakarta.validation.Validator; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; -import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import uk.gov.hmcts.reform.pip.account.management.database.UserRepository; -import uk.gov.hmcts.reform.pip.account.management.errorhandling.exceptions.AzureCustomException; import uk.gov.hmcts.reform.pip.account.management.errorhandling.exceptions.SystemAdminAccountException; -import uk.gov.hmcts.reform.pip.account.management.model.AzureAccount; import uk.gov.hmcts.reform.pip.account.management.model.PiUser; import uk.gov.hmcts.reform.pip.account.management.model.SystemAdminAccount; import uk.gov.hmcts.reform.pip.model.account.Roles; import uk.gov.hmcts.reform.pip.model.account.UserProvenances; -import uk.gov.hmcts.reform.pip.model.system.admin.ActionResult; -import uk.gov.hmcts.reform.pip.model.system.admin.CreateSystemAdminAction; +import java.util.Collections; import java.util.List; import java.util.Optional; import java.util.Set; @@ -31,23 +26,12 @@ import static org.junit.jupiter.api.Assertions.assertThrows; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.ArgumentMatchers.anyBoolean; -import static org.mockito.ArgumentMatchers.argThat; -import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.never; +import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @ExtendWith(MockitoExtension.class) class SystemAdminAccountServiceTest { - - @Mock - private AzureUserService azureUserService; - - @Mock - private PublicationService publicationService; - - @Mock - private AzureAccountService azureAccountService; - @Mock private UserRepository userRepository; @@ -68,189 +52,82 @@ class SystemAdminAccountServiceTest { private static final String SURNAME = "Surname"; private static final SystemAdminAccount SYSTEM_ADMIN_ACCOUNT = new SystemAdminAccount(EMAIL, FORENAME, SURNAME); private static final SystemAdminAccount ERRORED_SYSTEM_ADMIN_ACCOUNT = new SystemAdminAccount("abcd", FORENAME, - SURNAME); - private User expectedUser; + SURNAME); private PiUser expectedPiUser; @BeforeEach void setup() { - expectedUser = new User(); - expectedUser.setGivenName(FORENAME); - expectedUser.setId(ID); - expectedUser.setSurname(SURNAME); - expectedPiUser = new PiUser(); expectedPiUser.setUserId(UUID.randomUUID()); expectedPiUser.setEmail(EMAIL); expectedPiUser.setProvenanceUserId(ID); expectedPiUser.setRoles(Roles.SYSTEM_ADMIN); - expectedPiUser.setUserProvenance(UserProvenances.PI_AAD); + expectedPiUser.setUserProvenance(UserProvenances.SSO); - systemAdminAccountService = new SystemAdminAccountService(validator, azureUserService, userRepository, - publicationService, 4, - azureAccountService); + systemAdminAccountService = new SystemAdminAccountService(validator, userRepository, 4); } @Test - void testAddSystemAdminAccount() throws AzureCustomException { - AzureAccount azUser = new AzureAccount(); - azUser.setDisplayName(FORENAME); - - when(azureUserService.createUser(argThat(user -> EMAIL.equals(user.getEmail())), anyBoolean())) - .thenReturn(expectedUser); - when(userRepository.save(any())).thenReturn(expectedPiUser); - when(azureAccountService.retrieveAzureAccount(any())) - .thenReturn(azUser); - when(publicationService.sendNotificationEmail(EMAIL, FORENAME, SURNAME)).thenReturn(Boolean.TRUE); - when(userRepository.findByUserId(any())).thenReturn(Optional.ofNullable(expectedPiUser)); - when(validator.validate(SYSTEM_ADMIN_ACCOUNT)).thenReturn(Set.of()); + void testAddSystemAdminAccountSuccess() { + when(validator.validate(SYSTEM_ADMIN_ACCOUNT)).thenReturn(Collections.emptySet()); + when(userRepository.findByEmailAndUserProvenance(EMAIL, UserProvenances.SSO)) + .thenReturn(Optional.empty()); when(userRepository.findByRoles(Roles.SYSTEM_ADMIN)).thenReturn(List.of(expectedPiUser)); + when(userRepository.save(any())).thenReturn(expectedPiUser); - PiUser returnedUser = systemAdminAccountService.addSystemAdminAccount(SYSTEM_ADMIN_ACCOUNT, ID); + PiUser returnedUser = systemAdminAccountService.addSystemAdminAccount(SYSTEM_ADMIN_ACCOUNT); assertEquals(expectedPiUser, returnedUser, "returned user did not match expected"); } @Test - void testAddSystemAdminAccountThrowsException() throws AzureCustomException { - AzureAccount azUser = new AzureAccount(); - azUser.setDisplayName(FORENAME); - - when(userRepository.findByUserId(any())) - .thenReturn(Optional.ofNullable(expectedPiUser)); - when(azureAccountService.retrieveAzureAccount(any())) - .thenReturn(azUser); - when(azureUserService.createUser(argThat(user -> EMAIL.equals(user.getEmail())), anyBoolean())) - .thenThrow(new AzureCustomException("Test error")); - - SystemAdminAccountException systemAdminAccountException = - assertThrows(SystemAdminAccountException.class, () -> - systemAdminAccountService.addSystemAdminAccount(SYSTEM_ADMIN_ACCOUNT, ID)); - - - assertEquals("Test error", - systemAdminAccountException.getErroredSystemAdminAccount().getErrorMessages().get(0), - "Error message not as expected"); - } - - @Test - void testConstraintViolationException() { - AzureAccount azUser = new AzureAccount(); - azUser.setDisplayName(FORENAME); - - when(userRepository.findByUserId(any())) - .thenReturn(Optional.ofNullable(expectedPiUser)); - when(azureAccountService.retrieveAzureAccount(any())) - .thenReturn(azUser); + void testAddSystemAdminAccountConstraintViolation() { when(validator.validate(any())).thenReturn(Set.of(constraintViolation)); when(constraintViolation.getMessage()).thenReturn("This is a message"); when(constraintViolation.getPropertyPath()).thenReturn(path); SystemAdminAccountException systemAdminAccountException = assertThrows(SystemAdminAccountException.class, () -> - systemAdminAccountService.addSystemAdminAccount(ERRORED_SYSTEM_ADMIN_ACCOUNT, ID)); + systemAdminAccountService.addSystemAdminAccount(ERRORED_SYSTEM_ADMIN_ACCOUNT)); assertNotEquals(0, systemAdminAccountException.getErroredSystemAdminAccount().getErrorMessages().size(), - "Constraint violation error messages not displayed"); - } + "Constraint violation error messages not displayed"); - @Test - void testAddSystemAdminAccountNotVerified() throws AzureCustomException { - AzureAccount azUser = new AzureAccount(); - azUser.setDisplayName(FORENAME); - - expectedPiUser.setRoles(Roles.VERIFIED); - when(azureUserService.createUser(argThat(user -> EMAIL.equals(user.getEmail())), anyBoolean())) - .thenReturn(expectedUser); - when(userRepository.save(any())).thenReturn(expectedPiUser); - when(publicationService.sendNotificationEmail(EMAIL, FORENAME, SURNAME)).thenReturn(Boolean.FALSE); - when(userRepository.findByUserId(any())).thenReturn(Optional.ofNullable(expectedPiUser)); - when(validator.validate(SYSTEM_ADMIN_ACCOUNT)).thenReturn(Set.of()); - when(userRepository.findByRoles(Roles.SYSTEM_ADMIN)).thenReturn(List.of(expectedPiUser)); - - PiUser returnedUser = systemAdminAccountService.addSystemAdminAccount(SYSTEM_ADMIN_ACCOUNT, ID); - - assertEquals(expectedPiUser, returnedUser, "returned user did not match expected"); + verify(userRepository, never()).save(any()); } @Test - void testAddSystemAdminAccountNotExists() throws AzureCustomException { - AzureAccount azUser = new AzureAccount(); - azUser.setDisplayName(FORENAME); - - expectedPiUser.setRoles(Roles.VERIFIED); - when(azureUserService.createUser(argThat(user -> EMAIL.equals(user.getEmail())), anyBoolean())) - .thenReturn(expectedUser); - when(userRepository.save(any())).thenReturn(expectedPiUser); - when(publicationService.sendNotificationEmail(EMAIL, FORENAME, SURNAME)).thenReturn(Boolean.FALSE); - when(userRepository.findByUserId(any())).thenReturn(Optional.empty()); - when(validator.validate(SYSTEM_ADMIN_ACCOUNT)).thenReturn(Set.of()); - when(userRepository.findByRoles(Roles.SYSTEM_ADMIN)).thenReturn(List.of(expectedPiUser)); - - PiUser returnedUser = systemAdminAccountService.addSystemAdminAccount(SYSTEM_ADMIN_ACCOUNT, ID); - - assertEquals(expectedPiUser, returnedUser, "returned user did not match expected"); - } - - @Test - void testUserAlreadyExists() throws AzureCustomException { - AzureAccount azUser = new AzureAccount(); - azUser.setDisplayName(FORENAME); - when(userRepository.findByEmailAndUserProvenance(EMAIL, UserProvenances.PI_AAD)) + void testAddSystemAdminAccountUserAlreadyExists() { + when(validator.validate(SYSTEM_ADMIN_ACCOUNT)).thenReturn(Collections.emptySet()); + when(userRepository.findByEmailAndUserProvenance(EMAIL, UserProvenances.SSO)) .thenReturn(Optional.of(expectedPiUser)); - when(userRepository.findByUserId(any())) - .thenReturn(Optional.ofNullable(expectedPiUser)); - when(azureAccountService.retrieveAzureAccount(any())) - .thenReturn(azUser); SystemAdminAccountException systemAdminAccountException = assertThrows(SystemAdminAccountException.class, () -> - systemAdminAccountService.addSystemAdminAccount(SYSTEM_ADMIN_ACCOUNT, ID)); + systemAdminAccountService.addSystemAdminAccount(SYSTEM_ADMIN_ACCOUNT)); - assertTrue(systemAdminAccountException.getErroredSystemAdminAccount().isDuplicate(), "Duplicate account flag " - + "not set"); + assertTrue(systemAdminAccountException.getErroredSystemAdminAccount().isDuplicate(), + "Duplicate account flag not set"); + + verify(userRepository, never()).save(any()); } @Test - void testAboveMaxAllowsUsers() throws AzureCustomException { - AzureAccount azUser = new AzureAccount(); - azUser.setDisplayName(FORENAME); - when(userRepository.findByEmailAndUserProvenance(EMAIL, UserProvenances.PI_AAD)) + void testAddSystemAdminAccountAboveMaxAllowsUsers() { + when(validator.validate(SYSTEM_ADMIN_ACCOUNT)).thenReturn(Collections.emptySet()); + when(userRepository.findByEmailAndUserProvenance(EMAIL, UserProvenances.SSO)) .thenReturn(Optional.empty()); - when(userRepository.findByUserId(any())) - .thenReturn(Optional.ofNullable(expectedPiUser)); - when(azureAccountService.retrieveAzureAccount(any())) - .thenReturn(azUser); when(userRepository.findByRoles(Roles.SYSTEM_ADMIN)).thenReturn(List.of(expectedPiUser, expectedPiUser, expectedPiUser, expectedPiUser)); SystemAdminAccountException systemAdminAccountException = assertThrows(SystemAdminAccountException.class, () -> - systemAdminAccountService.addSystemAdminAccount(SYSTEM_ADMIN_ACCOUNT, ID)); - - assertTrue(systemAdminAccountException.getErroredSystemAdminAccount().isAboveMaxSystemAdmin(), "Max system " - + "admin flag not set"); - } - - @Test - void testHandleNewSystemAdminAccountAction() { - when(userRepository.findByRoles(Roles.SYSTEM_ADMIN)).thenReturn(List.of(expectedPiUser, expectedPiUser)); - - ArgumentCaptor systemAdminAccountArgumentCaptor = - ArgumentCaptor.forClass(CreateSystemAdminAction.class); - - doNothing().when(publicationService).sendSystemAdminAccountAction(systemAdminAccountArgumentCaptor.capture()); - - systemAdminAccountService.handleNewSystemAdminAccountAction(SYSTEM_ADMIN_ACCOUNT, ID, ActionResult.ATTEMPTED, - FORENAME); + systemAdminAccountService.addSystemAdminAccount(SYSTEM_ADMIN_ACCOUNT)); - CreateSystemAdminAction createSystemAdminAction = systemAdminAccountArgumentCaptor.getValue(); + assertTrue(systemAdminAccountException.getErroredSystemAdminAccount().isAboveMaxSystemAdmin(), + "Max system admin flag not set"); - assertEquals(EMAIL, createSystemAdminAction.getAccountEmail(), "Unknown email retrieved"); - assertEquals(FORENAME, createSystemAdminAction.getRequesterName(), "Unknown requester name retrieved"); - assertEquals(List.of(EMAIL, EMAIL), createSystemAdminAction.getEmailList(), "Unknown email list retrieved"); - assertEquals(ActionResult.ATTEMPTED, createSystemAdminAction.getActionResult(), - "Action result not as expected"); + verify(userRepository, never()).save(any()); } } diff --git a/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/SystemAdminB2CAccountServiceTest.java b/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/SystemAdminB2CAccountServiceTest.java new file mode 100644 index 00000000..130f1bdb --- /dev/null +++ b/src/test/java/uk/gov/hmcts/reform/pip/account/management/service/SystemAdminB2CAccountServiceTest.java @@ -0,0 +1,256 @@ +package uk.gov.hmcts.reform.pip.account.management.service; + +import com.microsoft.graph.models.User; +import jakarta.validation.ConstraintViolation; +import jakarta.validation.Path; +import jakarta.validation.Validator; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.ArgumentCaptor; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import uk.gov.hmcts.reform.pip.account.management.database.UserRepository; +import uk.gov.hmcts.reform.pip.account.management.errorhandling.exceptions.AzureCustomException; +import uk.gov.hmcts.reform.pip.account.management.errorhandling.exceptions.SystemAdminAccountException; +import uk.gov.hmcts.reform.pip.account.management.model.AzureAccount; +import uk.gov.hmcts.reform.pip.account.management.model.PiUser; +import uk.gov.hmcts.reform.pip.account.management.model.SystemAdminAccount; +import uk.gov.hmcts.reform.pip.model.account.Roles; +import uk.gov.hmcts.reform.pip.model.account.UserProvenances; +import uk.gov.hmcts.reform.pip.model.system.admin.ActionResult; +import uk.gov.hmcts.reform.pip.model.system.admin.CreateSystemAdminAction; + +import java.util.List; +import java.util.Optional; +import java.util.Set; +import java.util.UUID; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNotEquals; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.junit.jupiter.api.Assertions.assertTrue; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.argThat; +import static org.mockito.Mockito.doNothing; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class SystemAdminB2CAccountServiceTest { + + @Mock + private AzureUserService azureUserService; + + @Mock + private PublicationService publicationService; + + @Mock + private AzureAccountService azureAccountService; + + @Mock + private UserRepository userRepository; + + @Mock + private Validator validator; + + @Mock + private ConstraintViolation constraintViolation; + + @Mock + private Path path; + + private SystemAdminB2CAccountService systemAdminAccountService; + + private static final String ID = UUID.randomUUID().toString(); + private static final String EMAIL = "test@email.com"; + private static final String FORENAME = "Test"; + private static final String SURNAME = "Surname"; + private static final SystemAdminAccount SYSTEM_ADMIN_ACCOUNT = new SystemAdminAccount(EMAIL, FORENAME, SURNAME); + private static final SystemAdminAccount ERRORED_SYSTEM_ADMIN_ACCOUNT = new SystemAdminAccount("abcd", FORENAME, + SURNAME); + private User expectedUser; + private PiUser expectedPiUser; + + @BeforeEach + void setup() { + expectedUser = new User(); + expectedUser.setGivenName(FORENAME); + expectedUser.setId(ID); + expectedUser.setSurname(SURNAME); + + expectedPiUser = new PiUser(); + expectedPiUser.setUserId(UUID.randomUUID()); + expectedPiUser.setEmail(EMAIL); + expectedPiUser.setProvenanceUserId(ID); + expectedPiUser.setRoles(Roles.SYSTEM_ADMIN); + expectedPiUser.setUserProvenance(UserProvenances.PI_AAD); + + systemAdminAccountService = new SystemAdminB2CAccountService(validator, azureUserService, userRepository, + publicationService, 4, + azureAccountService); + + } + + @Test + void testAddSystemAdminAccount() throws AzureCustomException { + AzureAccount azUser = new AzureAccount(); + azUser.setDisplayName(FORENAME); + + when(azureUserService.createUser(argThat(user -> EMAIL.equals(user.getEmail())), anyBoolean())) + .thenReturn(expectedUser); + when(userRepository.save(any())).thenReturn(expectedPiUser); + when(azureAccountService.retrieveAzureAccount(any())) + .thenReturn(azUser); + when(publicationService.sendNotificationEmail(EMAIL, FORENAME, SURNAME)).thenReturn(Boolean.TRUE); + when(userRepository.findByUserId(any())).thenReturn(Optional.ofNullable(expectedPiUser)); + when(validator.validate(SYSTEM_ADMIN_ACCOUNT)).thenReturn(Set.of()); + when(userRepository.findByRoles(Roles.SYSTEM_ADMIN)).thenReturn(List.of(expectedPiUser)); + + PiUser returnedUser = systemAdminAccountService.addSystemAdminAccount(SYSTEM_ADMIN_ACCOUNT, ID); + + assertEquals(expectedPiUser, returnedUser, "returned user did not match expected"); + } + + @Test + void testAddSystemAdminAccountThrowsException() throws AzureCustomException { + AzureAccount azUser = new AzureAccount(); + azUser.setDisplayName(FORENAME); + + when(userRepository.findByUserId(any())) + .thenReturn(Optional.ofNullable(expectedPiUser)); + when(azureAccountService.retrieveAzureAccount(any())) + .thenReturn(azUser); + when(azureUserService.createUser(argThat(user -> EMAIL.equals(user.getEmail())), anyBoolean())) + .thenThrow(new AzureCustomException("Test error")); + + SystemAdminAccountException systemAdminAccountException = + assertThrows(SystemAdminAccountException.class, () -> + systemAdminAccountService.addSystemAdminAccount(SYSTEM_ADMIN_ACCOUNT, ID)); + + + assertEquals("Test error", + systemAdminAccountException.getErroredSystemAdminAccount().getErrorMessages().get(0), + "Error message not as expected"); + } + + @Test + void testConstraintViolationException() { + AzureAccount azUser = new AzureAccount(); + azUser.setDisplayName(FORENAME); + + when(userRepository.findByUserId(any())) + .thenReturn(Optional.ofNullable(expectedPiUser)); + when(azureAccountService.retrieveAzureAccount(any())) + .thenReturn(azUser); + when(validator.validate(any())).thenReturn(Set.of(constraintViolation)); + when(constraintViolation.getMessage()).thenReturn("This is a message"); + when(constraintViolation.getPropertyPath()).thenReturn(path); + + SystemAdminAccountException systemAdminAccountException = + assertThrows(SystemAdminAccountException.class, () -> + systemAdminAccountService.addSystemAdminAccount(ERRORED_SYSTEM_ADMIN_ACCOUNT, ID)); + + assertNotEquals(0, systemAdminAccountException.getErroredSystemAdminAccount().getErrorMessages().size(), + "Constraint violation error messages not displayed"); + } + + @Test + void testAddSystemAdminAccountNotVerified() throws AzureCustomException { + AzureAccount azUser = new AzureAccount(); + azUser.setDisplayName(FORENAME); + + expectedPiUser.setRoles(Roles.VERIFIED); + when(azureUserService.createUser(argThat(user -> EMAIL.equals(user.getEmail())), anyBoolean())) + .thenReturn(expectedUser); + when(userRepository.save(any())).thenReturn(expectedPiUser); + when(publicationService.sendNotificationEmail(EMAIL, FORENAME, SURNAME)).thenReturn(Boolean.FALSE); + when(userRepository.findByUserId(any())).thenReturn(Optional.ofNullable(expectedPiUser)); + when(validator.validate(SYSTEM_ADMIN_ACCOUNT)).thenReturn(Set.of()); + when(userRepository.findByRoles(Roles.SYSTEM_ADMIN)).thenReturn(List.of(expectedPiUser)); + + PiUser returnedUser = systemAdminAccountService.addSystemAdminAccount(SYSTEM_ADMIN_ACCOUNT, ID); + + assertEquals(expectedPiUser, returnedUser, "returned user did not match expected"); + } + + @Test + void testAddSystemAdminAccountNotExists() throws AzureCustomException { + AzureAccount azUser = new AzureAccount(); + azUser.setDisplayName(FORENAME); + + expectedPiUser.setRoles(Roles.VERIFIED); + when(azureUserService.createUser(argThat(user -> EMAIL.equals(user.getEmail())), anyBoolean())) + .thenReturn(expectedUser); + when(userRepository.save(any())).thenReturn(expectedPiUser); + when(publicationService.sendNotificationEmail(EMAIL, FORENAME, SURNAME)).thenReturn(Boolean.FALSE); + when(userRepository.findByUserId(any())).thenReturn(Optional.empty()); + when(validator.validate(SYSTEM_ADMIN_ACCOUNT)).thenReturn(Set.of()); + when(userRepository.findByRoles(Roles.SYSTEM_ADMIN)).thenReturn(List.of(expectedPiUser)); + + PiUser returnedUser = systemAdminAccountService.addSystemAdminAccount(SYSTEM_ADMIN_ACCOUNT, ID); + + assertEquals(expectedPiUser, returnedUser, "returned user did not match expected"); + } + + @Test + void testUserAlreadyExists() throws AzureCustomException { + AzureAccount azUser = new AzureAccount(); + azUser.setDisplayName(FORENAME); + when(userRepository.findByEmailAndUserProvenance(EMAIL, UserProvenances.PI_AAD)) + .thenReturn(Optional.of(expectedPiUser)); + when(userRepository.findByUserId(any())) + .thenReturn(Optional.ofNullable(expectedPiUser)); + when(azureAccountService.retrieveAzureAccount(any())) + .thenReturn(azUser); + + SystemAdminAccountException systemAdminAccountException = + assertThrows(SystemAdminAccountException.class, () -> + systemAdminAccountService.addSystemAdminAccount(SYSTEM_ADMIN_ACCOUNT, ID)); + + assertTrue(systemAdminAccountException.getErroredSystemAdminAccount().isDuplicate(), "Duplicate account flag " + + "not set"); + } + + @Test + void testAboveMaxAllowsUsers() throws AzureCustomException { + AzureAccount azUser = new AzureAccount(); + azUser.setDisplayName(FORENAME); + when(userRepository.findByEmailAndUserProvenance(EMAIL, UserProvenances.PI_AAD)) + .thenReturn(Optional.empty()); + when(userRepository.findByUserId(any())) + .thenReturn(Optional.ofNullable(expectedPiUser)); + when(azureAccountService.retrieveAzureAccount(any())) + .thenReturn(azUser); + when(userRepository.findByRoles(Roles.SYSTEM_ADMIN)).thenReturn(List.of(expectedPiUser, expectedPiUser, + expectedPiUser, expectedPiUser)); + + SystemAdminAccountException systemAdminAccountException = + assertThrows(SystemAdminAccountException.class, () -> + systemAdminAccountService.addSystemAdminAccount(SYSTEM_ADMIN_ACCOUNT, ID)); + + assertTrue(systemAdminAccountException.getErroredSystemAdminAccount().isAboveMaxSystemAdmin(), "Max system " + + "admin flag not set"); + } + + @Test + void testHandleNewSystemAdminAccountAction() { + when(userRepository.findByRoles(Roles.SYSTEM_ADMIN)).thenReturn(List.of(expectedPiUser, expectedPiUser)); + + ArgumentCaptor systemAdminAccountArgumentCaptor = + ArgumentCaptor.forClass(CreateSystemAdminAction.class); + + doNothing().when(publicationService).sendSystemAdminAccountAction(systemAdminAccountArgumentCaptor.capture()); + + systemAdminAccountService.handleNewSystemAdminAccountAction(SYSTEM_ADMIN_ACCOUNT, ID, ActionResult.ATTEMPTED, + FORENAME); + + CreateSystemAdminAction createSystemAdminAction = systemAdminAccountArgumentCaptor.getValue(); + + assertEquals(EMAIL, createSystemAdminAction.getAccountEmail(), "Unknown email retrieved"); + assertEquals(FORENAME, createSystemAdminAction.getRequesterName(), "Unknown requester name retrieved"); + assertEquals(List.of(EMAIL, EMAIL), createSystemAdminAction.getEmailList(), "Unknown email list retrieved"); + assertEquals(ActionResult.ATTEMPTED, createSystemAdminAction.getActionResult(), + "Action result not as expected"); + } +}