Skip to content

Commit e71db6c

Browse files
author
Alan Di Giovanni
committed
fix: [Auth] Fix auth error exceptions for more readability in logs
1 parent 06ad597 commit e71db6c

10 files changed

Lines changed: 68 additions & 45 deletions

File tree

src/main/java/com/cuoco/adapter/in/controller/UserControllerAdapter.java

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,7 @@
88
import com.cuoco.application.usecase.model.Allergy;
99
import com.cuoco.application.usecase.model.DietaryNeed;
1010
import com.cuoco.application.usecase.model.User;
11-
import com.cuoco.application.usecase.model.UserPreferences;
1211
import com.cuoco.shared.GlobalExceptionHandler;
13-
import com.cuoco.shared.utils.JwtUtil;
1412
import io.swagger.v3.oas.annotations.Operation;
1513
import io.swagger.v3.oas.annotations.media.Content;
1614
import io.swagger.v3.oas.annotations.media.Schema;

src/main/java/com/cuoco/adapter/in/security/JwtAuthenticationFilterAdapter.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
package com.cuoco.adapter.in.security;
22

3+
import com.cuoco.application.exception.UnauthorizedException;
34
import com.cuoco.application.port.in.AuthenticateUserCommand;
45
import com.cuoco.application.usecase.model.AuthenticatedUser;
56
import jakarta.servlet.FilterChain;
67
import jakarta.servlet.ServletException;
78
import jakarta.servlet.http.HttpServletRequest;
89
import jakarta.servlet.http.HttpServletResponse;
10+
import lombok.extern.slf4j.Slf4j;
911
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
1012
import org.springframework.security.core.authority.SimpleGrantedAuthority;
1113
import org.springframework.security.core.context.SecurityContextHolder;
@@ -17,6 +19,7 @@
1719
import java.io.IOException;
1820
import java.util.stream.Collectors;
1921

22+
@Slf4j
2023
@Component
2124
public class JwtAuthenticationFilterAdapter extends OncePerRequestFilter {
2225

@@ -30,18 +33,24 @@ public JwtAuthenticationFilterAdapter(AuthenticateUserCommand authenticateUserCo
3033
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
3134
throws ServletException, IOException {
3235

33-
final String authHeader = request.getHeader("Authorization");
36+
try {
37+
final String authHeader = request.getHeader("Authorization");
3438

35-
AuthenticatedUser authenticatedUser = authenticateUserCommand.execute(buildCommand(authHeader));
39+
AuthenticatedUser authenticatedUser = authenticateUserCommand.execute(buildCommand(authHeader));
3640

37-
if (authenticatedUser != null) {
38-
UsernamePasswordAuthenticationToken userToken = buildToken(authenticatedUser);
41+
if (authenticatedUser != null) {
42+
UsernamePasswordAuthenticationToken userToken = buildToken(authenticatedUser);
3943

40-
userToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
41-
SecurityContextHolder.getContext().setAuthentication(userToken);
42-
}
44+
userToken.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
45+
SecurityContextHolder.getContext().setAuthentication(userToken);
46+
}
47+
48+
filterChain.doFilter(request, response);
4349

44-
filterChain.doFilter(request, response);
50+
} catch (UnauthorizedException e) {
51+
log.warn("Unauthorized: {}", e.getDescription());
52+
response.sendError(HttpServletResponse.SC_UNAUTHORIZED, e.getDescription());
53+
}
4554
}
4655

4756
private AuthenticateUserCommand.Command buildCommand(String authHeader) {
@@ -66,6 +75,8 @@ protected boolean shouldNotFilter(HttpServletRequest request) {
6675
|| matcher.match("/diets", request.getRequestURI())
6776
|| matcher.match("/dietary-needs", request.getRequestURI())
6877
|| matcher.match("/cook-levels", request.getRequestURI())
78+
|| matcher.match("/meal-types", request.getRequestURI())
79+
|| matcher.match("/preparation-times", request.getRequestURI())
6980
|| matcher.match("/v3/api-docs/**", request.getRequestURI())
7081
|| matcher.match("/swagger-ui/**", request.getRequestURI())
7182
|| matcher.match("/swagger-ui.html", request.getRequestURI());

src/main/java/com/cuoco/application/usecase/AuthenticateUserUseCase.java

Lines changed: 13 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import com.cuoco.application.usecase.model.AuthenticatedUser;
77
import com.cuoco.application.usecase.model.User;
88
import com.cuoco.shared.model.ErrorDescription;
9-
import com.cuoco.shared.utils.JwtUtil;
9+
import com.cuoco.application.utils.JwtUtil;
1010
import lombok.extern.slf4j.Slf4j;
1111
import org.springframework.security.core.context.SecurityContextHolder;
1212
import org.springframework.stereotype.Component;
@@ -34,24 +34,29 @@ public AuthenticatedUser execute(Command command) {
3434

3535
String authHeader = command.getAuthHeader();
3636

37-
if (authHeader == null || !authHeader.startsWith(BEARER_PREFIX)) {
38-
log.info("User don't have a valid auth header");
39-
throw new UnauthorizedException(ErrorDescription.UNAUTHORIZED.getValue());
37+
if (authHeader == null) {
38+
log.info("Auth header is not present");
39+
throw new UnauthorizedException(ErrorDescription.NO_AUTH_TOKEN.getValue());
40+
}
41+
42+
if (!authHeader.startsWith(BEARER_PREFIX)) {
43+
log.info("Don't have a valid auth token");
44+
throw new UnauthorizedException(ErrorDescription.INVALID_CREDENTIALS.getValue());
4045
}
4146

4247
String receivedJwt = authHeader.substring(7);
4348
String email = jwtUtil.extractEmail(receivedJwt);
4449

4550
if (email == null || SecurityContextHolder.getContext().getAuthentication() != null) {
46-
log.info("Token is not valid. The email is not present.");
47-
throw new UnauthorizedException(ErrorDescription.INVALID_TOKEN.getValue());
51+
log.info("Token is not valid: The email is not present.");
52+
throw new UnauthorizedException(ErrorDescription.INVALID_CREDENTIALS.getValue());
4853
}
4954

5055
User user = getUserByEmailRepository.execute(email);
5156

5257
if (user == null || !jwtUtil.validateToken(receivedJwt, user)) {
53-
log.info("Token or user with email {} are not valid", email);
54-
throw new UnauthorizedException(ErrorDescription.INVALID_TOKEN.getValue());
58+
log.info("Token or user with email {} are not valid or not exists", email);
59+
throw new UnauthorizedException(ErrorDescription.INVALID_CREDENTIALS.getValue());
5560
}
5661

5762
log.info("User authenticated with email {}", email);

src/main/java/com/cuoco/application/usecase/SignInUserUseCase.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import com.cuoco.application.usecase.model.AuthenticatedUser;
77
import com.cuoco.application.usecase.model.User;
88
import com.cuoco.shared.model.ErrorDescription;
9-
import com.cuoco.shared.utils.JwtUtil;
9+
import com.cuoco.application.utils.JwtUtil;
1010
import lombok.extern.slf4j.Slf4j;
1111
import org.springframework.security.crypto.password.PasswordEncoder;
1212
import org.springframework.stereotype.Component;
@@ -42,9 +42,8 @@ public AuthenticatedUser execute(Command command) {
4242
}
4343

4444
user.setPassword(null);
45-
AuthenticatedUser authenticatedUser = buildAuthenticatedUser(user);
4645

47-
return authenticatedUser;
46+
return buildAuthenticatedUser(user);
4847
}
4948

5049
private AuthenticatedUser buildAuthenticatedUser(User user) {

src/main/java/com/cuoco/shared/utils/JwtUtil.java renamed to src/main/java/com/cuoco/application/utils/JwtUtil.java

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,19 @@
1-
package com.cuoco.shared.utils;
1+
package com.cuoco.application.utils;
22

3+
import com.cuoco.application.exception.UnauthorizedException;
34
import com.cuoco.application.usecase.model.User;
5+
import com.cuoco.shared.model.ErrorDescription;
46
import io.jsonwebtoken.Jwts;
7+
import io.jsonwebtoken.MalformedJwtException;
58
import io.jsonwebtoken.SignatureAlgorithm;
69
import io.jsonwebtoken.security.Keys;
10+
import lombok.extern.slf4j.Slf4j;
711
import org.springframework.beans.factory.annotation.Value;
812
import org.springframework.stereotype.Component;
913

1014
import java.util.Date;
1115

16+
@Slf4j
1217
@Component
1318
public class JwtUtil {
1419

@@ -25,13 +30,18 @@ public String generateToken(User user) {
2530
}
2631

2732
public String extractEmail(String token) {
28-
return Jwts.parserBuilder()
29-
.setSigningKey(Keys.hmacShaKeyFor(SECRET_KEY.getBytes()))
30-
.build()
31-
.parseClaimsJws(token)
32-
.getBody()
33-
.getSubject();
34-
33+
try {
34+
return Jwts.parserBuilder()
35+
.setSigningKey(Keys.hmacShaKeyFor(SECRET_KEY.getBytes()))
36+
.build()
37+
.parseClaimsJws(token)
38+
.getBody()
39+
.getSubject();
40+
41+
} catch (MalformedJwtException e) {
42+
log.warn("Invalid JWT token: {}", e.getMessage());
43+
throw new UnauthorizedException(ErrorDescription.INVALID_CREDENTIALS.getValue());
44+
}
3545
}
3646

3747
public boolean validateToken(String token, User user) {

src/main/java/com/cuoco/shared/config/security/SecurityConfiguration.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@ public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Excepti
3737
"/cook-levels",
3838
"/plans",
3939
"/diets",
40+
"/meal-types",
41+
"/preparation-times",
4042
"/dietary-needs",
4143
"/allergies",
4244
"/v3/api-docs/**",

src/main/java/com/cuoco/shared/model/ErrorDescription.java

Lines changed: 9 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
11
package com.cuoco.shared.model;
22

3+
import lombok.AllArgsConstructor;
4+
import lombok.Getter;
5+
6+
@Getter
7+
@AllArgsConstructor
38
public enum ErrorDescription {
49

510
RECIPE_NOT_EXISTS("El ID de la receta ingresada no existe"),
@@ -18,15 +23,16 @@ public enum ErrorDescription {
1823

1924
USER_NOT_EXISTS("El usuario ingresado no existe"),
2025
USER_DUPLICATED("El usuario ya existe"),
26+
NO_AUTH_TOKEN("El token no esta presente"),
2127
INVALID_CREDENTIALS("Las credenciales no son válidas"),
22-
INVALID_TOKEN("El token no es valido"),
23-
EXPIRED_TOKEN("El token ha expirado"),
28+
EXPIRED_CREDENTIALS("El token ha expirado"),
2429

2530
INVALID_AUDIO_FILE_EXTENSION("La extensión del archivo de audio no es valida"),
2631
AUDIO_FILE_IS_REQUIRED("El archivo de audio no esta presente y es requerido"),
2732
AUDIO_FILE_PROCESSING_ERROR("Error procesando el archivo de audio"),
2833
PRO_FEATURE("Esta funcionalidad solo es para usuarios PRO"),
29-
UNAUTHORIZED("El token no esta presente"),
34+
35+
UNAUTHORIZED("No está autorizado a usar esta función"),
3036
UNEXPECTED_ERROR("An unexpected error occurred: "),
3137
UNHANDLED("Ha ocurrido un error inesperado"),
3238
NOT_AVAILABLE("El servicio no esta disponible"),
@@ -35,12 +41,4 @@ public enum ErrorDescription {
3541
DUPLICATED("El recurso ya existe");
3642

3743
private final String value;
38-
39-
ErrorDescription(String value) {
40-
this.value = value;
41-
}
42-
43-
public String getValue() {
44-
return value;
45-
}
4644
}

src/test/java/com/cuoco/adapter/in/controller/UserControllerAdapterTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import com.cuoco.application.port.in.UpdateUserProfileCommand;
55
import com.cuoco.application.usecase.model.User;
66
import com.cuoco.factory.domain.UserFactory;
7-
import com.cuoco.shared.utils.JwtUtil;
7+
import com.cuoco.application.utils.JwtUtil;
88
import com.fasterxml.jackson.databind.ObjectMapper;
99
import org.junit.jupiter.api.BeforeEach;
1010
import org.junit.jupiter.api.Test;

src/test/java/com/cuoco/application/usecase/AuthenticateUserUseCaseTest.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import com.cuoco.application.usecase.model.User;
88
import com.cuoco.factory.domain.UserFactory;
99
import com.cuoco.shared.model.ErrorDescription;
10-
import com.cuoco.shared.utils.JwtUtil;
10+
import com.cuoco.application.utils.JwtUtil;
1111
import org.junit.jupiter.api.BeforeEach;
1212
import org.junit.jupiter.api.Test;
1313

@@ -72,7 +72,7 @@ void GIVEN_token_with_null_email_WHEN_execute_THEN_throw_invalid_token() {
7272
when(jwtUtil.extractEmail(token)).thenReturn(null);
7373

7474
UnauthorizedException ex = assertThrows(UnauthorizedException.class, () -> useCase.execute(command));
75-
assertEquals(ErrorDescription.INVALID_TOKEN.getValue(), ex.getDescription());
75+
assertEquals(ErrorDescription.INVALID_CREDENTIALS.getValue(), ex.getDescription());
7676
}
7777

7878
@Test
@@ -87,6 +87,6 @@ void GIVEN_invalid_user_or_token_WHEN_execute_THEN_throw_invalid_token() {
8787
when(getUserByEmailRepository.execute(email)).thenReturn(null);
8888

8989
UnauthorizedException ex = assertThrows(UnauthorizedException.class, () -> useCase.execute(command));
90-
assertEquals(ErrorDescription.INVALID_TOKEN.getValue(), ex.getDescription());
90+
assertEquals(ErrorDescription.INVALID_CREDENTIALS.getValue(), ex.getDescription());
9191
}
9292
}

src/test/java/com/cuoco/application/usecase/SignInUserUseCaseTest.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import com.cuoco.application.usecase.model.AuthenticatedUser;
77
import com.cuoco.application.usecase.model.User;
88
import com.cuoco.shared.model.ErrorDescription;
9-
import com.cuoco.shared.utils.JwtUtil;
9+
import com.cuoco.application.utils.JwtUtil;
1010
import org.junit.jupiter.api.BeforeEach;
1111
import org.junit.jupiter.api.Test;
1212
import org.springframework.security.crypto.password.PasswordEncoder;

0 commit comments

Comments
 (0)