Cześć,
moja konfiguracja spring security jest skoncentrowana na zabezpieczaniu endpointów. Podział ról USER/ADMIN. Napisałem takie testy, jestem ciekaw co o nich myślicie.
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureMockMvc
@ActiveProfiles("test")
public class DeleteUserControllerSecurityTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private DataSource dataSource;
private Long userId;
@BeforeEach
void init() throws Exception {
try(Connection connection = dataSource.getConnection()) {
ScriptUtils.executeSqlScript(connection, new ClassPathResource("data_sql/test-data-setup.sql"));
final String usernameToDelete = "testSecondUsername";
this.userId = DatabaseTestHelper.getUserIdByUsername(dataSource, usernameToDelete);
}
}
@AfterEach
void cleanup() {
JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
jdbcTemplate.update("DELETE FROM user_roles");
jdbcTemplate.update("DELETE FROM users");
jdbcTemplate.update("DELETE FROM roles");
}
@Test
void shouldAllowDeletionForUserWithProperRole() throws Exception {
final String requestBody = "{\"usernameOrEmail\": \"testAdmin\",\"password\": \"testPassword@123\"}";
String jwtToken = AuthenticationTestHelper.loginAndGetToken(mockMvc, requestBody);
Cookie cookie = new Cookie("auth_token", jwtToken);
DeleteRequestAssertions.assertDeleteStatusReturns(
mockMvc, "/api/v1/users/" + userId, cookie, 200);
}
@Test
@WithAnonymousUser
void shouldReturnUnauthorizedForUnauthenticatedUser() throws Exception {
DeleteRequestAssertions.assertDeleteStatusReturns(
mockMvc, "/api/v1/users/" + userId, null, 401);
}
@Test
@WithAnonymousUser
void shouldReturnUnauthorizedMessageForUnauthenticatedUser() throws Exception {
final String expectedMessage = "Unauthorized access. Please log in.";
DeleteRequestAssertions.assertDeleteResponse(mockMvc, "/api/v1/users/" + userId,
null, expectedMessage);
}
@Test
void shouldReturnStatusForbiddenWhenUserWithInsufficientPrivilegesTriesToDeleteUser() throws Exception {
final String requestBody = "{\"usernameOrEmail\": \"testUsername\",\"password\": \"testPassword@123\"}";
String jwtToken = AuthenticationTestHelper.loginAndGetToken(mockMvc, requestBody);
Cookie cookie = new Cookie("auth_token", jwtToken);
DeleteRequestAssertions.assertDeleteStatusReturns(
mockMvc, "/api/v1/users/" + userId, cookie, 403);
}
@Test
void shouldReturnForbiddenMessageWhenUserWithInsufficientPrivilegesTriesToDeleteUser() throws Exception {
final String requestBody = "{\"usernameOrEmail\": \"testUsername\",\"password\": \"testPassword@123\"}";
final String expectedMessage = "You do not have permission to perform this operation.";
String jwtToken = AuthenticationTestHelper.loginAndGetToken(mockMvc, requestBody);
Cookie cookie = new Cookie("auth_token", jwtToken);
DeleteRequestAssertions.assertDeleteResponse(mockMvc, "/api/v1/users/" + userId,
cookie, expectedMessage);
}
}
Klasy pomocnicze
public class DeleteRequestAssertions {
public static void assertDeleteStatusReturns(MockMvc mockMvc, String endpoint, Cookie cookie,
int expectedStatusCode) throws Exception {
MockHttpServletRequestBuilder requestBuilder = delete(endpoint);
if (cookie != null) {
requestBuilder.cookie(cookie);
}
mockMvc.perform(requestBuilder)
.andExpect(status().is(expectedStatusCode));
}
public static void assertDeleteResponse(MockMvc mockMvc, String endpoint, Cookie jwtCookie,
String expectedMessage) throws Exception {
MockHttpServletRequestBuilder requestBuilder = delete(endpoint);
if (jwtCookie != null) {
requestBuilder.cookie(jwtCookie);
}
mockMvc.perform(requestBuilder)
.andExpect(content().string(containsString(expectedMessage)));
}
}
public class DatabaseTestHelper {
public static Long getUserIdByUsername(DataSource dataSource, String username) throws SQLException {
String query = "SELECT id FROM users WHERE username = ?";
try (Connection connection = dataSource.getConnection();
PreparedStatement statement = connection.prepareStatement(query)) {
statement.setString(1, username);
ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
return resultSet.getLong("id");
} else {
return null;
}
}
}
}
public class AuthenticationTestHelper {
public static String loginAndGetToken(MockMvc mockMvc, String requestBody) throws Exception {
MvcResult mvcResult = mockMvc.perform(post("/api/v1/users/login")
.contentType(MediaType.APPLICATION_JSON)
.content(requestBody))
.andExpect(status().isOk())
.andReturn();
String responseString = mvcResult.getResponse().getContentAsString();
return JsonPath.parse(responseString).read("$.accessToken");
}
}
Dzięki za pomoc.