diff --git a/support-portal-backend/pom.xml b/support-portal-backend/pom.xml
index f414d90..addf18c 100644
--- a/support-portal-backend/pom.xml
+++ b/support-portal-backend/pom.xml
@@ -84,6 +84,13 @@
test
+
+ org.apache.httpcomponents
+ httpclient
+ 4.5.13
+ test
+
+
diff --git a/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/controller/UserResourceTest.java b/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/controller/UserResourceTest.java
index 2f192eb..69cdc12 100644
--- a/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/controller/UserResourceTest.java
+++ b/support-portal-backend/src/test/java/net/shyshkin/study/fullstack/supportportal/backend/controller/UserResourceTest.java
@@ -6,6 +6,7 @@ import net.shyshkin.study.fullstack.supportportal.backend.common.BaseUserTest;
import net.shyshkin.study.fullstack.supportportal.backend.domain.HttpResponse;
import net.shyshkin.study.fullstack.supportportal.backend.domain.User;
import net.shyshkin.study.fullstack.supportportal.backend.domain.UserPrincipal;
+import net.shyshkin.study.fullstack.supportportal.backend.service.LoginAttemptService;
import net.shyshkin.study.fullstack.supportportal.backend.utility.JwtTokenProvider;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Order;
@@ -266,4 +267,64 @@ class UserResourceTest extends BaseUserTest {
log.debug("Token: {}", token);
assertThat(token).isNull();
}
+
+ @Test
+ @Order(60)
+ void loginUser_bruteForceDetectionTest() throws InterruptedException {
+
+ //given
+ User fakeUser = createRandomUser();
+ String correctPassword = fakeUser.getPassword().replace("{noop}", "");
+ String username = fakeUser.getUsername();
+ userRepository.save(fakeUser);
+ String wrongPassword = "wrongPass";
+
+ //when
+ User userLogin = User.builder()
+ .username(username)
+ .password(wrongPassword)
+ .build();
+
+ for (int i = 0; i < LoginAttemptService.MAX_ATTEMPTS; i++) {
+
+ var responseEntity = restTemplate.postForEntity("/user/login", userLogin, HttpResponse.class);
+
+ //then
+ log.debug("Response Entity: {}", responseEntity);
+ assertThat(responseEntity.getStatusCode()).isEqualTo(BAD_REQUEST);
+ assertThat(responseEntity.getBody())
+ .isNotNull()
+ .hasNoNullFieldsOrProperties()
+ .hasFieldOrPropertyWithValue("httpStatusCode", 400)
+ .hasFieldOrPropertyWithValue("httpStatus", BAD_REQUEST)
+ .hasFieldOrPropertyWithValue("reason", "BAD REQUEST")
+ .hasFieldOrPropertyWithValue("message", "USERNAME / PASSWORD INCORRECT. PLEASE TRY AGAIN");
+ }
+
+ for (int i = 0; i < 5; i++) {
+
+ if (i > 3) {
+ // Even correct password should not allow access to locked account
+ userLogin = User.builder()
+ .username(username)
+ .password(correctPassword)
+ .build();
+ }
+
+ var responseEntity = restTemplate.postForEntity("/user/login", userLogin, HttpResponse.class);
+
+ //then
+ log.debug("Response Entity: {}", responseEntity);
+ assertThat(responseEntity.getStatusCode()).isEqualTo(UNAUTHORIZED);
+ assertThat(responseEntity.getBody())
+ .isNotNull()
+ .hasNoNullFieldsOrProperties()
+ .hasFieldOrPropertyWithValue("httpStatusCode", 401)
+ .hasFieldOrPropertyWithValue("httpStatus", UNAUTHORIZED)
+ .hasFieldOrPropertyWithValue("reason", "UNAUTHORIZED")
+ .hasFieldOrPropertyWithValue("message", "YOUR ACCOUNT HAS BEEN LOCKED. PLEASE CONTACT ADMINISTRATION");
+ }
+
+
+ }
}
\ No newline at end of file