diff --git a/build.gradle b/build.gradle index f14d023..b533db0 100644 --- a/build.gradle +++ b/build.gradle @@ -8,7 +8,7 @@ plugins { } group = 'com.flexcodelabs' -version = '0.0.28' +version = '0.0.29' description = 'Flextuma App' java { diff --git a/src/main/java/com/flexcodelabs/flextuma/core/config/RequestLoggingFilter.java b/src/main/java/com/flexcodelabs/flextuma/core/config/RequestLoggingFilter.java index be380f6..8637d8d 100644 --- a/src/main/java/com/flexcodelabs/flextuma/core/config/RequestLoggingFilter.java +++ b/src/main/java/com/flexcodelabs/flextuma/core/config/RequestLoggingFilter.java @@ -4,16 +4,22 @@ import jakarta.servlet.ServletException; import jakarta.servlet.http.HttpServletRequest; import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.Ordered; import org.springframework.core.annotation.Order; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.web.context.HttpSessionSecurityContextRepository; import org.springframework.stereotype.Component; import org.springframework.web.filter.OncePerRequestFilter; import java.io.IOException; +import java.security.Principal; + +import com.flexcodelabs.flextuma.core.security.AuthenticatedUserCaptureFilter; @Component @Order(Ordered.HIGHEST_PRECEDENCE) @@ -43,9 +49,6 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse logRequest(request, response, fullUri, startTime, 500, ex); throw ex; } finally { - // Only log in finally if we haven't already logged via the catch block - // OR we rely on the response status. Best is to extract the logging logic - // into a helper method. if (request.getAttribute("REQUEST_LOGGED") == null) { logRequest(request, response, fullUri, startTime, response.getStatus(), null); } @@ -67,7 +70,7 @@ private void logRequest(HttpServletRequest request, HttpServletResponse response return; } request.setAttribute("REQUEST_LOGGED", true); - String username = getUsername(); + String username = getUsername(request); long duration = System.currentTimeMillis() - startTime; int status = statusOverride > 0 ? statusOverride : response.getStatus(); @@ -95,10 +98,21 @@ private void logRequest(HttpServletRequest request, HttpServletResponse response } } - private String getUsername() { + private String getUsername(HttpServletRequest request) { + Object capturedUsername = request.getAttribute(AuthenticatedUserCaptureFilter.REQUEST_USERNAME_ATTRIBUTE); + if (capturedUsername instanceof String username + && !username.trim().isEmpty() + && !"SYSTEM".equalsIgnoreCase(username)) { + return username; + } + + Principal principal = request.getUserPrincipal(); + if (principal != null && principal.getName() != null && !principal.getName().trim().isEmpty()) { + return principal.getName(); + } + Authentication auth = SecurityContextHolder.getContext().getAuthentication(); - // Debug logging to understand the authentication context log.debug("Authentication found: {}", auth != null); if (auth != null) { log.debug("Auth class: {}", auth.getClass().getSimpleName()); @@ -113,15 +127,28 @@ private String getUsername() { if (auth != null && auth.isAuthenticated() && !"anonymousUser".equals(auth.getPrincipal())) { String username = auth.getName(); - // Don't return "SYSTEM" for actual authenticated users if (username != null && !username.trim().isEmpty() && !"SYSTEM".equalsIgnoreCase(username)) { log.debug("Returning username: {}", username); return username; } } - // For login requests, try to extract username from request parameters - HttpServletRequest request = getCurrentRequest(); + HttpSession session = request.getSession(false); + if (session != null) { + Object contextAttr = session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY); + if (contextAttr instanceof SecurityContext securityContext) { + Authentication sessionAuth = securityContext.getAuthentication(); + if (sessionAuth != null && sessionAuth.isAuthenticated() + && !"anonymousUser".equals(sessionAuth.getPrincipal())) { + String sessionUsername = sessionAuth.getName(); + if (sessionUsername != null && !sessionUsername.trim().isEmpty() + && !"SYSTEM".equalsIgnoreCase(sessionUsername)) { + return sessionUsername; + } + } + } + } + if (request != null && request.getRequestURI().contains("/login")) { String loginUsername = request.getParameter(USERNAME_KEY); if (loginUsername != null && !loginUsername.trim().isEmpty()) { @@ -132,17 +159,4 @@ private String getUsername() { log.debug("Returning SYSTEM as fallback"); return "SYSTEM"; } - - private HttpServletRequest getCurrentRequest() { - try { - org.springframework.web.context.request.RequestAttributes attrs = org.springframework.web.context.request.RequestContextHolder - .getRequestAttributes(); - if (attrs instanceof org.springframework.web.context.request.ServletRequestAttributes servletRequestAttributes) { - return servletRequestAttributes.getRequest(); - } - } catch (Exception e) { - log.debug("❌❌❌❌ [RequestLoggingFilter] Could not get current request: {} ❌❌❌❌", e.getMessage()); - } - return null; - } -} \ No newline at end of file +} diff --git a/src/main/java/com/flexcodelabs/flextuma/core/config/auth/ApiKeyAuthProperties.java b/src/main/java/com/flexcodelabs/flextuma/core/config/auth/ApiKeyAuthProperties.java new file mode 100644 index 0000000..9e5f4d2 --- /dev/null +++ b/src/main/java/com/flexcodelabs/flextuma/core/config/auth/ApiKeyAuthProperties.java @@ -0,0 +1,13 @@ +package com.flexcodelabs.flextuma.core.config.auth; + +import org.springframework.boot.context.properties.ConfigurationProperties; +import org.springframework.boot.context.properties.bind.DefaultValue; +import org.springframework.validation.annotation.Validated; + +import java.util.List; + +@Validated +@ConfigurationProperties(prefix = "flextuma.auth") +public record ApiKeyAuthProperties( + @DefaultValue("/api/webhooks/**,/api/external/**") List apiKeyEndpoints) { +} \ No newline at end of file diff --git a/src/main/java/com/flexcodelabs/flextuma/core/filters/TraceIdFilter.java b/src/main/java/com/flexcodelabs/flextuma/core/filters/TraceIdFilter.java index b200482..12ac55f 100644 --- a/src/main/java/com/flexcodelabs/flextuma/core/filters/TraceIdFilter.java +++ b/src/main/java/com/flexcodelabs/flextuma/core/filters/TraceIdFilter.java @@ -35,12 +35,19 @@ protected void doFilterInternal(HttpServletRequest request, HttpServletResponse MDC.put(TRACE_ID_KEY, traceId); response.setHeader(TRACE_HEADER, traceId); + String username = resolveUsername(); + if (username != null) { + MDC.put(USERNAME_KEY, username); + } + try { filterChain.doFilter(request, response); - String username = resolveUsername(); - if (username != null) { - MDC.put(USERNAME_KEY, username); + if (username == null) { + String resolvedAfterChain = resolveUsername(); + if (resolvedAfterChain != null) { + MDC.put(USERNAME_KEY, resolvedAfterChain); + } } } finally { MDC.remove(TRACE_ID_KEY); diff --git a/src/main/java/com/flexcodelabs/flextuma/core/helpers/DynamicFetchSpecification.java b/src/main/java/com/flexcodelabs/flextuma/core/helpers/DynamicFetchSpecification.java index f32a6b7..b566f71 100644 --- a/src/main/java/com/flexcodelabs/flextuma/core/helpers/DynamicFetchSpecification.java +++ b/src/main/java/com/flexcodelabs/flextuma/core/helpers/DynamicFetchSpecification.java @@ -35,19 +35,16 @@ public DynamicFetchSpecification(Set fieldPaths) { @Override public Predicate toPredicate(Root root, CriteriaQuery query, CriteriaBuilder cb) { - // Fetch joins are not allowed in count queries Class resultType = query.getResultType(); if (resultType == Long.class || resultType == long.class || resultType == Integer.class || resultType == int.class) { return cb.conjunction(); } - // Apply fetch joins for requested paths for (String path : fieldPaths) { applyFetch(root, path); } - // Use distinct to avoid duplicates when fetching collections query.distinct(true); return cb.conjunction(); diff --git a/src/main/java/com/flexcodelabs/flextuma/core/security/AuthenticatedUserCaptureFilter.java b/src/main/java/com/flexcodelabs/flextuma/core/security/AuthenticatedUserCaptureFilter.java new file mode 100644 index 0000000..fcca2e5 --- /dev/null +++ b/src/main/java/com/flexcodelabs/flextuma/core/security/AuthenticatedUserCaptureFilter.java @@ -0,0 +1,36 @@ +package com.flexcodelabs.flextuma.core.security; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.springframework.security.authentication.AnonymousAuthenticationToken; +import org.springframework.security.core.Authentication; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; + +import java.io.IOException; + +@Component +public class AuthenticatedUserCaptureFilter extends OncePerRequestFilter { + + public static final String REQUEST_USERNAME_ATTRIBUTE = "flextuma.authenticated.username"; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + try { + filterChain.doFilter(request, response); + } finally { + Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); + if (authentication != null + && authentication.isAuthenticated() + && !(authentication instanceof AnonymousAuthenticationToken) + && authentication.getName() != null + && !authentication.getName().isBlank()) { + request.setAttribute(REQUEST_USERNAME_ATTRIBUTE, authentication.getName()); + } + } + } +} diff --git a/src/main/java/com/flexcodelabs/flextuma/core/security/SecurityConfig.java b/src/main/java/com/flexcodelabs/flextuma/core/security/SecurityConfig.java index b3e049c..8c915f4 100644 --- a/src/main/java/com/flexcodelabs/flextuma/core/security/SecurityConfig.java +++ b/src/main/java/com/flexcodelabs/flextuma/core/security/SecurityConfig.java @@ -25,13 +25,16 @@ public class SecurityConfig { private final CustomSecurityExceptionHandler securityExceptionHandler; private final PatAuthenticationFilter patAuthenticationFilter; private final PasswordChangeRequiredFilter passwordChangeRequiredFilter; + private final AuthenticatedUserCaptureFilter authenticatedUserCaptureFilter; public SecurityConfig(CustomSecurityExceptionHandler securityExceptionHandler, PatAuthenticationFilter patAuthenticationFilter, - PasswordChangeRequiredFilter passwordChangeRequiredFilter) { + PasswordChangeRequiredFilter passwordChangeRequiredFilter, + AuthenticatedUserCaptureFilter authenticatedUserCaptureFilter) { this.securityExceptionHandler = securityExceptionHandler; this.patAuthenticationFilter = patAuthenticationFilter; this.passwordChangeRequiredFilter = passwordChangeRequiredFilter; + this.authenticatedUserCaptureFilter = authenticatedUserCaptureFilter; } @Bean @@ -63,6 +66,7 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) { org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.class) .addFilterAfter(passwordChangeRequiredFilter, org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.class) + .addFilterAfter(authenticatedUserCaptureFilter, PasswordChangeRequiredFilter.class) .exceptionHandling(ex -> ex .authenticationEntryPoint(securityExceptionHandler) .accessDeniedHandler(securityExceptionHandler)) @@ -76,4 +80,4 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) { throw new BeanCreationException("Security Filter Chain creation failed", e); } } -} \ No newline at end of file +} diff --git a/src/main/java/com/flexcodelabs/flextuma/modules/auth/controllers/AuthController.java b/src/main/java/com/flexcodelabs/flextuma/modules/auth/controllers/AuthController.java index 520f95d..217fc07 100644 --- a/src/main/java/com/flexcodelabs/flextuma/modules/auth/controllers/AuthController.java +++ b/src/main/java/com/flexcodelabs/flextuma/modules/auth/controllers/AuthController.java @@ -3,9 +3,7 @@ import java.math.BigDecimal; import org.springframework.beans.factory.annotation.Value; -import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; -import org.springframework.http.ResponseCookie; import org.springframework.http.ResponseEntity; import org.springframework.security.authentication.AnonymousAuthenticationToken; import org.springframework.security.core.Authentication; @@ -27,7 +25,6 @@ import com.flexcodelabs.flextuma.core.exceptions.RateLimitExceededException; import com.flexcodelabs.flextuma.core.entities.auth.User; import com.flexcodelabs.flextuma.core.services.AuthRateLimitService; -import com.flexcodelabs.flextuma.core.services.CookieService; import com.flexcodelabs.flextuma.core.services.SecurityLogService; import com.flexcodelabs.flextuma.core.services.VerificationService; import com.flexcodelabs.flextuma.modules.auth.services.AuthenticationResult; @@ -45,7 +42,6 @@ public class AuthController { private final UserService userService; - private final CookieService cookieService; private final WalletService walletService; private final AuthRateLimitService rateLimitService; private final SecurityLogService securityLogService; @@ -95,26 +91,34 @@ public ResponseEntity login( AuthenticationResult authResult = userService.authenticateAndCreateContext( request.getUsername(), request.getPassword(), httpRequest, httpResponse); - ResponseCookie cookie = cookieService.createAuthCookie(); - rateLimitService.recordSuccessfulAttempt(httpRequest); securityLogService.logLoginAttempt(authResult.user().getUsername(), httpRequest, true, "Login successful"); return ResponseEntity.ok() - .header(HttpHeaders.SET_COOKIE, cookie.toString()) .body(authResult.user()); } @PostMapping("/logout") - public ResponseEntity logout(HttpServletRequest request) { + public ResponseEntity logout(HttpServletRequest request, HttpServletResponse response) { Authentication auth = SecurityContextHolder.getContext().getAuthentication(); if (auth != null && auth.isAuthenticated() && !(auth instanceof AnonymousAuthenticationToken)) { securityLogService.logLogout(auth.getName(), request); } - return ResponseEntity.ok() - .header(HttpHeaders.SET_COOKIE, cookieService.deleteAuthCookie().toString()) - .build(); + + jakarta.servlet.http.HttpSession session = request.getSession(false); + if (session != null) { + session.invalidate(); + } + SecurityContextHolder.clearContext(); + + jakarta.servlet.http.Cookie cookie = new jakarta.servlet.http.Cookie("SESSION", ""); + cookie.setHttpOnly(true); + cookie.setPath("/"); + cookie.setMaxAge(0); + response.addCookie(cookie); + + return ResponseEntity.ok().build(); } @GetMapping("/me") diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index 190222a..d5225e1 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -49,7 +49,7 @@ logging.level.org.springframework.web=WARN spring.web.error.include-message=${ERROR_INCLUDE_MESSAGE:always} # SMS Pricing -flextuma.sms.price-per-segment=${SMS_PRICE_PER_SEGMENT:20.0} +flextuma.sms.price-per-segment=${SMS_PRICE_PER_SEGMENT:} # App Upload Directories flextuma.app.upload.directory=${APP_UPLOAD_DIRECTORY:/tmp/apps} diff --git a/src/test/java/com/flexcodelabs/flextuma/core/config/RequestLoggingFilterTest.java b/src/test/java/com/flexcodelabs/flextuma/core/config/RequestLoggingFilterTest.java new file mode 100644 index 0000000..dadcbfb --- /dev/null +++ b/src/test/java/com/flexcodelabs/flextuma/core/config/RequestLoggingFilterTest.java @@ -0,0 +1,106 @@ +package com.flexcodelabs.flextuma.core.config; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import jakarta.servlet.http.HttpSession; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContext; +import org.springframework.security.core.context.SecurityContextImpl; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.web.context.HttpSessionSecurityContextRepository; + +import java.io.IOException; +import java.security.Principal; + +import com.flexcodelabs.flextuma.core.security.AuthenticatedUserCaptureFilter; + +import static org.mockito.ArgumentMatchers.anyString; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.verify; +import static org.mockito.Mockito.when; + +@ExtendWith(MockitoExtension.class) +class RequestLoggingFilterTest { + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + @Mock + private FilterChain filterChain; + + @Mock + private HttpSession session; + + private RequestLoggingFilter filter; + + @BeforeEach + void setUp() { + filter = new RequestLoggingFilter(); + SecurityContextHolder.clearContext(); + } + + @Test + void shouldUseRequestPrincipalWhenSecurityContextIsUnavailable() throws ServletException, IOException { + Principal principal = mock(Principal.class); + + when(request.getRequestURI()).thenReturn("/api/me"); + when(request.getQueryString()).thenReturn(null); + when(request.getUserPrincipal()).thenReturn(principal); + when(principal.getName()).thenReturn("bennett"); + when(response.getStatus()).thenReturn(200); + + filter.doFilterInternal(request, response, filterChain); + + verify(filterChain).doFilter(request, response); + verify(request).getUserPrincipal(); + } + + @Test + void shouldUseCapturedUsernameAttributeBeforeOtherFallbacks() throws ServletException, IOException { + when(request.getRequestURI()).thenReturn("/api/tags"); + when(request.getQueryString()).thenReturn(null); + when(request.getAttribute(anyString())).thenAnswer(invocation -> { + String key = invocation.getArgument(0, String.class); + if (AuthenticatedUserCaptureFilter.REQUEST_USERNAME_ATTRIBUTE.equals(key)) { + return "admin"; + } + return null; + }); + when(response.getStatus()).thenReturn(200); + + filter.doFilterInternal(request, response, filterChain); + + verify(filterChain).doFilter(request, response); + verify(request).getAttribute(AuthenticatedUserCaptureFilter.REQUEST_USERNAME_ATTRIBUTE); + } + + @Test + void shouldUseSessionSecurityContextWhenPrincipalAndThreadContextAreUnavailable() + throws ServletException, IOException { + SecurityContext sessionContext = new SecurityContextImpl( + new UsernamePasswordAuthenticationToken("admin", null, java.util.List.of())); + + when(request.getRequestURI()).thenReturn("/api/lists"); + when(request.getQueryString()).thenReturn(null); + when(request.getUserPrincipal()).thenReturn(null); + when(request.getSession(false)).thenReturn(session); + when(session.getAttribute(HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY)) + .thenReturn(sessionContext); + when(response.getStatus()).thenReturn(200); + + filter.doFilterInternal(request, response, filterChain); + + verify(filterChain).doFilter(request, response); + verify(request).getSession(false); + } +} diff --git a/src/test/java/com/flexcodelabs/flextuma/core/filters/TraceIdFilterUsernameTest.java b/src/test/java/com/flexcodelabs/flextuma/core/filters/TraceIdFilterUsernameTest.java new file mode 100644 index 0000000..76b5731 --- /dev/null +++ b/src/test/java/com/flexcodelabs/flextuma/core/filters/TraceIdFilterUsernameTest.java @@ -0,0 +1,112 @@ +package com.flexcodelabs.flextuma.core.filters; + +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; +import org.slf4j.MDC; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.authority.SimpleGrantedAuthority; +import org.springframework.security.core.context.SecurityContextHolder; + +import java.io.IOException; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.*; +import static org.mockito.Mockito.*; + +@ExtendWith(MockitoExtension.class) +class TraceIdFilterUsernameTest { + + @Mock + private HttpServletRequest request; + + @Mock + private HttpServletResponse response; + + @Mock + private FilterChain filterChain; + + private TraceIdFilter traceIdFilter; + + @BeforeEach + void setUp() { + traceIdFilter = new TraceIdFilter(); + SecurityContextHolder.clearContext(); + MDC.clear(); + } + + @Test + void shouldSetUsernameInMDCWhenUserIsAuthenticated() throws ServletException, IOException { + // Arrange + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + "testuser", null, List.of(new SimpleGrantedAuthority("ROLE_USER"))); + SecurityContextHolder.getContext().setAuthentication(authentication); + + // Act - use a custom filter chain that checks MDC before cleanup + FilterChain customFilterChain = new FilterChain() { + @Override + public void doFilter(jakarta.servlet.ServletRequest request, jakarta.servlet.ServletResponse response) + throws IOException, ServletException { + // Check MDC value during filter execution (before cleanup) + String usernameDuringExecution = MDC.get("username"); + System.out.println("MDC username during execution: " + usernameDuringExecution); + assertEquals("testuser", usernameDuringExecution); + } + }; + + traceIdFilter.doFilterInternal(request, response, customFilterChain); + + // Assert - MDC should be cleaned up after filter execution + assertNull(MDC.get("username")); + assertNull(MDC.get("traceId")); + } + + @Test + void shouldNotSetUsernameWhenUserIsAnonymous() throws ServletException, IOException { + // Arrange - no authentication set + + // Act + traceIdFilter.doFilterInternal(request, response, filterChain); + + // Assert + assertNull(MDC.get("username")); + verify(filterChain).doFilter(request, response); + } + + @Test + void shouldNotSetUsernameWhenUserIsNotAuthenticated() throws ServletException, IOException { + // Arrange + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + "testuser", null, List.of()); + authentication.setAuthenticated(false); + SecurityContextHolder.getContext().setAuthentication(authentication); + + // Act + traceIdFilter.doFilterInternal(request, response, filterChain); + + // Assert + assertNull(MDC.get("username")); + verify(filterChain).doFilter(request, response); + } + + @Test + void shouldCleanUpMDCAfterFilterChain() throws ServletException, IOException { + // Arrange + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + "testuser", null, List.of(new SimpleGrantedAuthority("ROLE_USER"))); + SecurityContextHolder.getContext().setAuthentication(authentication); + + // Act + traceIdFilter.doFilterInternal(request, response, filterChain); + + // Assert - MDC should be cleaned up after filter execution + assertNull(MDC.get("username")); + assertNull(MDC.get("traceId")); + } +} diff --git a/src/test/java/com/flexcodelabs/flextuma/modules/auth/controllers/AuthControllerTest.java b/src/test/java/com/flexcodelabs/flextuma/modules/auth/controllers/AuthControllerTest.java index e05ef33..eb414a7 100644 --- a/src/test/java/com/flexcodelabs/flextuma/modules/auth/controllers/AuthControllerTest.java +++ b/src/test/java/com/flexcodelabs/flextuma/modules/auth/controllers/AuthControllerTest.java @@ -14,7 +14,6 @@ import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import org.springframework.http.MediaType; -import org.springframework.http.ResponseCookie; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; @@ -22,7 +21,6 @@ import com.flexcodelabs.flextuma.core.dtos.LoginDto; import com.flexcodelabs.flextuma.core.entities.auth.User; import com.flexcodelabs.flextuma.core.services.AuthRateLimitService; -import com.flexcodelabs.flextuma.core.services.CookieService; import com.flexcodelabs.flextuma.core.services.SecurityLogService; import com.flexcodelabs.flextuma.core.services.VerificationService; import com.flexcodelabs.flextuma.modules.auth.services.AuthenticationResult; @@ -40,9 +38,6 @@ class AuthControllerTest { @Mock private UserService userService; - @Mock - private CookieService cookieService; - @Mock private WalletService walletService; @@ -65,13 +60,13 @@ class AuthControllerTest { @BeforeEach void setUp() { - AuthController controller = new AuthController(userService, cookieService, walletService, rateLimitService, + AuthController controller = new AuthController(userService, walletService, rateLimitService, securityLogService, verificationService); mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); } @Test - void login_shouldReturnUserAndSetCookie_whenCredentialsValid() throws Exception { + void login_shouldReturnUser_whenCredentialsValid() throws Exception { LoginDto loginDto = new LoginDto(); loginDto.setUsername("user"); loginDto.setPassword("password"); @@ -80,11 +75,9 @@ void login_shouldReturnUserAndSetCookie_whenCredentialsValid() throws Exception user.setUsername("user"); user.setRoles(new java.util.HashSet<>()); - ResponseCookie cookie = ResponseCookie.from("SESSION", "token").build(); AuthenticationResult authResult = new AuthenticationResult(user, null); when(userService.authenticateAndCreateContext(eq("user"), eq("password"), any(), any())).thenReturn(authResult); - when(cookieService.createAuthCookie()).thenReturn(cookie); when(rateLimitService.isBlocked(any())).thenReturn(false); doNothing().when(rateLimitService).recordSuccessfulAttempt(any()); doNothing().when(securityLogService).logLoginAttempt(any(), any(), eq(true), any()); @@ -93,15 +86,11 @@ void login_shouldReturnUserAndSetCookie_whenCredentialsValid() throws Exception .contentType(MediaType.APPLICATION_JSON) .content(objectMapper.writeValueAsString(loginDto))) .andExpect(status().isOk()) - .andExpect(header().exists("Set-Cookie")) .andExpect(jsonPath("$.username").value("user")); } @Test void logout_shouldDeleteCookie() throws Exception { - ResponseCookie cookie = ResponseCookie.from("SESSION", "").maxAge(0).build(); - when(cookieService.deleteAuthCookie()).thenReturn(cookie); - // Mock authentication context when(authentication.getName()).thenReturn("testuser"); when(authentication.isAuthenticated()).thenReturn(true);