|
@@ -1,5 +1,6 @@
|
|
|
package com.danielbohry.authservice.service.auth;
|
|
package com.danielbohry.authservice.service.auth;
|
|
|
|
|
|
|
|
|
|
+import com.danielbohry.authservice.JwtTestUtils;
|
|
|
import com.danielbohry.authservice.api.dto.AuthenticationRequest;
|
|
import com.danielbohry.authservice.api.dto.AuthenticationRequest;
|
|
|
import com.danielbohry.authservice.api.dto.AuthenticationResponse;
|
|
import com.danielbohry.authservice.api.dto.AuthenticationResponse;
|
|
|
import com.danielbohry.authservice.client.MailClient;
|
|
import com.danielbohry.authservice.client.MailClient;
|
|
@@ -18,11 +19,14 @@ import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
|
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
import org.springframework.security.crypto.password.PasswordEncoder;
|
|
|
|
|
|
|
|
import java.time.Instant;
|
|
import java.time.Instant;
|
|
|
|
|
+import java.time.temporal.ChronoUnit;
|
|
|
|
|
+import java.util.Date;
|
|
|
import java.util.List;
|
|
import java.util.List;
|
|
|
|
|
|
|
|
import static org.junit.jupiter.api.Assertions.*;
|
|
import static org.junit.jupiter.api.Assertions.*;
|
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
|
import static org.mockito.ArgumentMatchers.anyString;
|
|
import static org.mockito.ArgumentMatchers.anyString;
|
|
|
|
|
+import static org.mockito.ArgumentMatchers.eq;
|
|
|
import static org.mockito.Mockito.*;
|
|
import static org.mockito.Mockito.*;
|
|
|
|
|
|
|
|
class AuthServiceTest {
|
|
class AuthServiceTest {
|
|
@@ -262,4 +266,192 @@ class AuthServiceTest {
|
|
|
"password123".equals(auth.getCredentials())
|
|
"password123".equals(auth.getCredentials())
|
|
|
));
|
|
));
|
|
|
}
|
|
}
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void shouldReturnExistingTokenWhenNotNearExpiration() {
|
|
|
|
|
+ // given
|
|
|
|
|
+ String currentToken = "valid-jwt-token";
|
|
|
|
|
+ Date tokenExpiration = new Date(System.currentTimeMillis() + (2 * 60 * 60 * 1000));
|
|
|
|
|
+ List<String> authorities = List.of("USER");
|
|
|
|
|
+
|
|
|
|
|
+ when(userService.findByUsername("testuser")).thenReturn(testUser);
|
|
|
|
|
+ when(jwtService.isTokenExpired(currentToken)).thenReturn(false);
|
|
|
|
|
+ when(jwtService.isTokenNearExpiration(currentToken)).thenReturn(false);
|
|
|
|
|
+ when(jwtService.extractExpiration(currentToken)).thenReturn(tokenExpiration);
|
|
|
|
|
+ when(jwtService.extractClaim(eq(currentToken), any())).thenReturn(authorities);
|
|
|
|
|
+ when(jwtService.generateToken(testUser)).thenReturn(testAuthentication);
|
|
|
|
|
+
|
|
|
|
|
+ // when
|
|
|
|
|
+ AuthenticationResponse result = authService.refresh(testUser, currentToken);
|
|
|
|
|
+
|
|
|
|
|
+ // then
|
|
|
|
|
+ assertNotNull(result);
|
|
|
|
|
+ assertEquals(testUser.getId(), result.getId());
|
|
|
|
|
+ assertEquals(testUser.getUsername(), result.getUsername());
|
|
|
|
|
+ assertEquals(testUser.getEmail(), result.getEmail());
|
|
|
|
|
+ assertEquals(currentToken, result.getToken());
|
|
|
|
|
+ assertEquals(tokenExpiration.toInstant(), result.getExpirationDate());
|
|
|
|
|
+ assertEquals(List.of("USER"), result.getRoles());
|
|
|
|
|
+
|
|
|
|
|
+ verify(userService).findByUsername("testuser");
|
|
|
|
|
+ verify(jwtService).isTokenExpired(currentToken);
|
|
|
|
|
+ verify(jwtService).isTokenNearExpiration(currentToken);
|
|
|
|
|
+ verify(jwtService).extractExpiration(currentToken);
|
|
|
|
|
+ verify(userService, never()).update(anyString(), any(ApplicationUser.class));
|
|
|
|
|
+ verify(jwtService, never()).generateToken(any(ApplicationUser.class));
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void shouldGenerateNewTokenWhenNearExpiration() {
|
|
|
|
|
+ // given
|
|
|
|
|
+ String currentToken = JwtTestUtils.createTokenWithExpiration("testuser", 15, ChronoUnit.MINUTES);
|
|
|
|
|
+
|
|
|
|
|
+ when(userService.findByUsername("testuser")).thenReturn(testUser);
|
|
|
|
|
+ when(jwtService.isTokenExpired(currentToken)).thenReturn(false);
|
|
|
|
|
+ when(jwtService.isTokenNearExpiration(currentToken)).thenReturn(true);
|
|
|
|
|
+ when(jwtService.generateToken(testUser)).thenReturn(testAuthentication);
|
|
|
|
|
+
|
|
|
|
|
+ // when
|
|
|
|
|
+ AuthenticationResponse result = authService.refresh(testUser, currentToken);
|
|
|
|
|
+
|
|
|
|
|
+ // then
|
|
|
|
|
+ assertNotNull(result);
|
|
|
|
|
+ assertEquals(testUser.getId(), result.getId());
|
|
|
|
|
+ assertEquals(testUser.getUsername(), result.getUsername());
|
|
|
|
|
+ assertEquals(testUser.getEmail(), result.getEmail());
|
|
|
|
|
+ assertEquals("jwt-token-123", result.getToken()); // Should return new token
|
|
|
|
|
+ assertEquals(testAuthentication.expirationDate(), result.getExpirationDate());
|
|
|
|
|
+ assertEquals(List.of("ROLE_USER"), result.getRoles());
|
|
|
|
|
+
|
|
|
|
|
+ verify(userService).findByUsername("testuser");
|
|
|
|
|
+ verify(jwtService).isTokenExpired(currentToken);
|
|
|
|
|
+ verify(jwtService).isTokenNearExpiration(currentToken);
|
|
|
|
|
+ verify(jwtService).generateToken(testUser);
|
|
|
|
|
+ verify(userService).update(testUser.getId(), testUser); // Should update lastLoginAt
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void shouldGenerateNewTokenWhenTokenIsExpired() {
|
|
|
|
|
+ // given
|
|
|
|
|
+ String expiredToken = JwtTestUtils.createExpiredToken("testuser");
|
|
|
|
|
+
|
|
|
|
|
+ when(userService.findByUsername("testuser")).thenReturn(testUser);
|
|
|
|
|
+ when(jwtService.isTokenExpired(expiredToken)).thenReturn(true);
|
|
|
|
|
+ when(jwtService.generateToken(testUser)).thenReturn(testAuthentication);
|
|
|
|
|
+
|
|
|
|
|
+ // when
|
|
|
|
|
+ AuthenticationResponse result = authService.refresh(testUser, expiredToken);
|
|
|
|
|
+
|
|
|
|
|
+ // then
|
|
|
|
|
+ assertNotNull(result);
|
|
|
|
|
+ assertEquals(testUser.getId(), result.getId());
|
|
|
|
|
+ assertEquals(testUser.getUsername(), result.getUsername());
|
|
|
|
|
+ assertEquals(testUser.getEmail(), result.getEmail());
|
|
|
|
|
+ assertEquals("jwt-token-123", result.getToken()); // Should return new token
|
|
|
|
|
+ assertEquals(testAuthentication.expirationDate(), result.getExpirationDate());
|
|
|
|
|
+ assertEquals(List.of("ROLE_USER"), result.getRoles());
|
|
|
|
|
+
|
|
|
|
|
+ verify(userService).findByUsername("testuser");
|
|
|
|
|
+ verify(jwtService).isTokenExpired(expiredToken);
|
|
|
|
|
+ verify(jwtService).generateToken(testUser);
|
|
|
|
|
+ verify(userService).update(testUser.getId(), testUser); // Should update lastLoginAt
|
|
|
|
|
+ verify(jwtService, never()).isTokenNearExpiration(expiredToken); // Should not check near expiration if already expired
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void shouldGenerateNewTokenWhenCurrentTokenIsNull() {
|
|
|
|
|
+ // given
|
|
|
|
|
+ when(userService.findByUsername("testuser")).thenReturn(testUser);
|
|
|
|
|
+ when(jwtService.generateToken(testUser)).thenReturn(testAuthentication);
|
|
|
|
|
+
|
|
|
|
|
+ // when
|
|
|
|
|
+ AuthenticationResponse result = authService.refresh(testUser, null);
|
|
|
|
|
+
|
|
|
|
|
+ // then
|
|
|
|
|
+ assertNotNull(result);
|
|
|
|
|
+ assertEquals(testUser.getId(), result.getId());
|
|
|
|
|
+ assertEquals(testUser.getUsername(), result.getUsername());
|
|
|
|
|
+ assertEquals(testUser.getEmail(), result.getEmail());
|
|
|
|
|
+ assertEquals("jwt-token-123", result.getToken()); // Should return new token
|
|
|
|
|
+ assertEquals(testAuthentication.expirationDate(), result.getExpirationDate());
|
|
|
|
|
+ assertEquals(List.of("ROLE_USER"), result.getRoles());
|
|
|
|
|
+
|
|
|
|
|
+ verify(userService).findByUsername("testuser");
|
|
|
|
|
+ verify(jwtService).generateToken(testUser);
|
|
|
|
|
+ verify(userService).update(testUser.getId(), testUser); // Should update lastLoginAt
|
|
|
|
|
+ verify(jwtService, never()).isTokenExpired(any());
|
|
|
|
|
+ verify(jwtService, never()).isTokenNearExpiration(any());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void shouldGenerateNewTokenWhenRolesHaveChanged() {
|
|
|
|
|
+ // given
|
|
|
|
|
+ String currentToken = "valid-jwt-token";
|
|
|
|
|
+ Date tokenExpiration = new Date(System.currentTimeMillis() + (2 * 60 * 60 * 1000)); // 2 hours from now
|
|
|
|
|
+ List<String> tokenAuthorities = List.of("ROLE_USER"); // Token has only USER role
|
|
|
|
|
+
|
|
|
|
|
+ // User now has ADMIN role in addition to USER
|
|
|
|
|
+ ApplicationUser userWithNewRoles = ApplicationUser.builder()
|
|
|
|
|
+ .id("user-id-123")
|
|
|
|
|
+ .username("testuser")
|
|
|
|
|
+ .password("encodedPassword")
|
|
|
|
|
+ .email("test@example.com")
|
|
|
|
|
+ .roles(List.of(Role.ADMIN, Role.USER))
|
|
|
|
|
+ .active(true)
|
|
|
|
|
+ .build();
|
|
|
|
|
+
|
|
|
|
|
+ when(userService.findByUsername("testuser")).thenReturn(userWithNewRoles);
|
|
|
|
|
+ when(jwtService.isTokenExpired(currentToken)).thenReturn(false);
|
|
|
|
|
+ when(jwtService.isTokenNearExpiration(currentToken)).thenReturn(false);
|
|
|
|
|
+ when(jwtService.extractExpiration(currentToken)).thenReturn(tokenExpiration);
|
|
|
|
|
+ when(jwtService.extractClaim(eq(currentToken), any())).thenReturn(tokenAuthorities);
|
|
|
|
|
+ when(jwtService.generateToken(userWithNewRoles)).thenReturn(testAuthentication);
|
|
|
|
|
+
|
|
|
|
|
+ // when
|
|
|
|
|
+ AuthenticationResponse result = authService.refresh(testUser, currentToken);
|
|
|
|
|
+
|
|
|
|
|
+ // then
|
|
|
|
|
+ assertNotNull(result);
|
|
|
|
|
+ assertEquals(userWithNewRoles.getId(), result.getId());
|
|
|
|
|
+ assertEquals(userWithNewRoles.getUsername(), result.getUsername());
|
|
|
|
|
+ assertEquals(userWithNewRoles.getEmail(), result.getEmail());
|
|
|
|
|
+ assertEquals("jwt-token-123", result.getToken()); // Should return new token
|
|
|
|
|
+ assertEquals(testAuthentication.expirationDate(), result.getExpirationDate());
|
|
|
|
|
+ assertEquals(List.of("ROLE_USER"), result.getRoles()); // From new token
|
|
|
|
|
+
|
|
|
|
|
+ verify(userService).findByUsername("testuser");
|
|
|
|
|
+ verify(jwtService).isTokenExpired(currentToken);
|
|
|
|
|
+ verify(jwtService).isTokenNearExpiration(currentToken);
|
|
|
|
|
+ verify(jwtService).extractClaim(eq(currentToken), any());
|
|
|
|
|
+ verify(jwtService).generateToken(userWithNewRoles); // Should generate new token
|
|
|
|
|
+ verify(userService).update(userWithNewRoles.getId(), userWithNewRoles); // Should update lastLoginAt
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ @Test
|
|
|
|
|
+ void shouldReturnNullWhenUserIsInactive() {
|
|
|
|
|
+ // given
|
|
|
|
|
+ ApplicationUser inactiveUser = ApplicationUser.builder()
|
|
|
|
|
+ .id("inactive-user-id")
|
|
|
|
|
+ .username("inactiveuser")
|
|
|
|
|
+ .password("encodedPassword")
|
|
|
|
|
+ .email("inactive@example.com")
|
|
|
|
|
+ .roles(List.of(Role.USER))
|
|
|
|
|
+ .active(false)
|
|
|
|
|
+ .build();
|
|
|
|
|
+
|
|
|
|
|
+ String currentToken = JwtTestUtils.createValidToken("inactiveuser");
|
|
|
|
|
+
|
|
|
|
|
+ // when
|
|
|
|
|
+ AuthenticationResponse result = authService.refresh(inactiveUser, currentToken);
|
|
|
|
|
+
|
|
|
|
|
+ // then
|
|
|
|
|
+ assertNull(result);
|
|
|
|
|
+
|
|
|
|
|
+ verify(userService, never()).findByUsername(anyString());
|
|
|
|
|
+ verify(jwtService, never()).isTokenExpired(any());
|
|
|
|
|
+ verify(jwtService, never()).isTokenNearExpiration(any());
|
|
|
|
|
+ verify(jwtService, never()).generateToken(any());
|
|
|
|
|
+ verify(userService, never()).update(anyString(), any());
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
}
|
|
}
|