From 9be3a9ae2352cdb376a255a86601463139f8d6f7 Mon Sep 17 00:00:00 2001 From: Szymon Radziszewski Date: Thu, 19 Sep 2024 14:50:24 +0200 Subject: [PATCH] OIS-46: Added tests for provider class --- .../security/OlmisAuthenticationProvider.java | 1 + .../org/openlmis/auth/UserDataBuilder.java | 7 + .../OlmisAuthenticationProviderTest.java | 145 ++++++++++++++++++ .../auth/service/UserServiceTest.java | 2 +- 4 files changed, 154 insertions(+), 1 deletion(-) create mode 100644 src/test/java/org/openlmis/auth/security/OlmisAuthenticationProviderTest.java diff --git a/src/main/java/org/openlmis/auth/security/OlmisAuthenticationProvider.java b/src/main/java/org/openlmis/auth/security/OlmisAuthenticationProvider.java index 901772e..5263431 100644 --- a/src/main/java/org/openlmis/auth/security/OlmisAuthenticationProvider.java +++ b/src/main/java/org/openlmis/auth/security/OlmisAuthenticationProvider.java @@ -78,4 +78,5 @@ protected void additionalAuthenticationChecks(UserDetails userDetails, } } + } diff --git a/src/test/java/org/openlmis/auth/UserDataBuilder.java b/src/test/java/org/openlmis/auth/UserDataBuilder.java index 0c3dca5..500c178 100644 --- a/src/test/java/org/openlmis/auth/UserDataBuilder.java +++ b/src/test/java/org/openlmis/auth/UserDataBuilder.java @@ -26,12 +26,18 @@ public class UserDataBuilder { private String username = "user" + instanceNumber.incrementAndGet(); private boolean enabled = true; private String password = null; + private boolean lockedOut = false; public UserDataBuilder withPassword(String password) { this.password = password; return this; } + public UserDataBuilder asLockedOut(boolean lockedOut) { + this.lockedOut = lockedOut; + return this; + } + /** * Builds instance of {@link User} without id. */ @@ -41,6 +47,7 @@ public User build() { user.setUsername(username); user.setEnabled(enabled); user.setPassword(password); + user.setLockedOut(lockedOut); return user; } diff --git a/src/test/java/org/openlmis/auth/security/OlmisAuthenticationProviderTest.java b/src/test/java/org/openlmis/auth/security/OlmisAuthenticationProviderTest.java new file mode 100644 index 0000000..121bffd --- /dev/null +++ b/src/test/java/org/openlmis/auth/security/OlmisAuthenticationProviderTest.java @@ -0,0 +1,145 @@ +/* + * This program is part of the OpenLMIS logistics management information system platform software. + * Copyright © 2017 VillageReach + * + * This program is free software: you can redistribute it and/or modify it under the terms + * of the GNU Affero General Public License as published by the Free Software Foundation, either + * version 3 of the License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. + * See the GNU Affero General Public License for more details. You should have received a copy of + * the GNU Affero General Public License along with this program. If not, see + * http://www.gnu.org/licenses.  For additional information contact info@OpenLMIS.org. + */ + +package org.openlmis.auth.security; + +import static org.junit.Assert.assertFalse; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.assertTrue; +import static org.junit.jupiter.api.Assertions.assertThrows; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.doThrow; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +import java.time.ZonedDateTime; +import java.util.Optional; +import java.util.UUID; +import org.assertj.core.internal.Objects; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.MockitoJUnitRunner; +import org.openlmis.auth.UserDataBuilder; +import org.openlmis.auth.domain.UnsuccessfulAuthenticationAttempt; +import org.openlmis.auth.domain.User; +import org.openlmis.auth.repository.UnsuccessfulAuthenticationAttemptRepository; +import org.openlmis.auth.repository.UserRepository; +import org.springframework.security.authentication.BadCredentialsException; +import org.springframework.security.authentication.LockedException; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.crypto.password.PasswordEncoder; +import org.springframework.test.util.ReflectionTestUtils; + +@RunWith(MockitoJUnitRunner.class) +public class OlmisAuthenticationProviderTest { + + @Mock + private UserRepository userRepository; + + @Mock + private UnsuccessfulAuthenticationAttemptRepository unsuccessfulAuthenticationAttemptRepository; + + @Mock + private UserDetails userDetails; + + @Mock + private UsernamePasswordAuthenticationToken authentication; + + @Mock + private PasswordEncoder passwordEncoder; + + @InjectMocks + private OlmisAuthenticationProvider olmisAuthenticationProvider; + + private User user; + private UnsuccessfulAuthenticationAttempt attempt; + + @Before + public void setUp() { + ReflectionTestUtils.setField(olmisAuthenticationProvider, "maxUnsuccessfulAuthAttempts", 3); + ReflectionTestUtils.setField(olmisAuthenticationProvider, "lockoutTime", 60); + + user = new UserDataBuilder().build(); + attempt = new UnsuccessfulAuthenticationAttempt(user); + + when(userRepository.findOneByUsernameIgnoreCase(anyString())).thenReturn(user); + when(userDetails.getUsername()).thenReturn(user.getUsername()); + when(unsuccessfulAuthenticationAttemptRepository.findByUserId(any(UUID.class))) + .thenReturn(Optional.of(attempt)); + } + + @Test(expected = LockedException.class) + public void shouldThrowExceptionIfUserLockedOutAndLockoutNotExpired() { + // given + user.setLockedOut(true); + attempt.setLastUnsuccessfulAuthenticationAttemptDate(ZonedDateTime.now().minusSeconds(30)); + + // when + olmisAuthenticationProvider.additionalAuthenticationChecks(userDetails, authentication); + } + + @Test(expected = BadCredentialsException.class) + public void shouldThrowExceptionIfAuthenticationFail() { + // given + doThrow(new BadCredentialsException("Bad credentials")).when(authentication).getCredentials(); + + // when + olmisAuthenticationProvider.additionalAuthenticationChecks(userDetails, authentication); + } + + @Test + public void shouldUnlockLockedOutUserIfLockoutExpired() { + // given + when(authentication.getCredentials()).thenReturn(Objects.instance()); + when(userDetails.getPassword()).thenReturn("test-password"); + when(passwordEncoder.matches(anyString(), anyString())).thenReturn(Boolean.TRUE); + user.setLockedOut(true); + attempt.setLastUnsuccessfulAuthenticationAttemptDate(ZonedDateTime.now().minusSeconds(61)); + + // when + olmisAuthenticationProvider.additionalAuthenticationChecks(userDetails, authentication); + + // then + assertFalse(user.isLockedOut()); + verify(userRepository).save(user); + verify(unsuccessfulAuthenticationAttemptRepository).save(attempt); + } + + @Test + public void shouldLockOutUserIfExceedsMaxAttemptNumber() { + // given + user.setLockedOut(false); + attempt.setAttemptCounter(2); + doThrow(new BadCredentialsException("Bad credentials")).when(authentication).getCredentials(); + + // when + BadCredentialsException exception = + assertThrows(BadCredentialsException.class, () -> + olmisAuthenticationProvider.additionalAuthenticationChecks(userDetails, authentication) + ); + + // then + assertNotNull(exception); + assertTrue(user.isLockedOut()); + verify(userRepository).save(user); + verify(unsuccessfulAuthenticationAttemptRepository).save(attempt); + } + +} diff --git a/src/test/java/org/openlmis/auth/service/UserServiceTest.java b/src/test/java/org/openlmis/auth/service/UserServiceTest.java index b2c4eca..fb26a27 100644 --- a/src/test/java/org/openlmis/auth/service/UserServiceTest.java +++ b/src/test/java/org/openlmis/auth/service/UserServiceTest.java @@ -28,7 +28,7 @@ import org.junit.runner.RunWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.runners.MockitoJUnitRunner; +import org.mockito.junit.MockitoJUnitRunner; import org.openlmis.auth.SaveAnswer; import org.openlmis.auth.UserDataBuilder; import org.openlmis.auth.domain.User;