-
Notifications
You must be signed in to change notification settings - Fork 0
Fix/login logout endpoints #94
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
2443444
e1556a1
cf2917e
83bcbcb
ff4dd27
81258f2
f4bf553
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change | ||||
---|---|---|---|---|---|---|
|
@@ -86,7 +86,7 @@ public RefreshTokenResponseDTO refreshToken(String token) { | |||||
throw new AuthenticationException("Refresh token não fornecido"); | ||||||
} | ||||||
|
||||||
if (jwtTokenProvider.isTokenExpired(token) || !jwtTokenProvider.validateToken(token)) { | ||||||
if (!jwtTokenProvider.isTokenValid(token)) { | ||||||
throw new AuthenticationException("Refresh token inválido ou expirado"); | ||||||
} | ||||||
|
||||||
|
@@ -113,14 +113,15 @@ public RefreshTokenResponseDTO refreshToken(String token) { | |||||
} | ||||||
|
||||||
public Boolean logout(String accessToken, String refreshToken) { | ||||||
if (!jwtTokenProvider.validateToken(accessToken) || jwtTokenProvider.isTokenExpired(accessToken)) { | ||||||
if (!jwtTokenProvider.isTokenValid(accessToken)) { | ||||||
throw new AuthenticationException("Access token inválido ou expirado"); | ||||||
} | ||||||
if (!jwtTokenProvider.validateToken(refreshToken) || jwtTokenProvider.isTokenExpired(refreshToken)) { | ||||||
if (!jwtTokenProvider.isTokenValid(refreshToken)) { | ||||||
throw new AuthenticationException("Refresh token inválido ou expirado"); | ||||||
} | ||||||
|
||||||
memoryBlacklistService.addToBlacklist(accessToken); | ||||||
memoryBlacklistService.addToBlacklist(refreshToken); | ||||||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Adicionar o refresh token à blacklist pode ser problemático se o mesmo refresh token for usado para gerar novos access tokens. Considere se é necessário invalidar o refresh token imediatamente ou se deveria ser invalidado apenas quando expirar naturalmente, dependendo da estratégia de rotação de tokens do sistema.
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||
|
||||||
return true; | ||||||
} | ||||||
|
Original file line number | Diff line number | Diff line change | ||||||
---|---|---|---|---|---|---|---|---|
|
@@ -38,14 +38,22 @@ protected void doFilterInternal( | |||||||
filterChain.doFilter(request, response); | ||||||||
return; | ||||||||
} | ||||||||
if (memoryBlacklistService.isBlacklisted(authHeader.substring(7))) { | ||||||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); | ||||||||
response.getWriter().write("Token inválido"); | ||||||||
return; | ||||||||
|
||||||||
// Extrair token do header uma vez para evitar duplicação | ||||||||
final String token = authHeader.substring(7); | ||||||||
|
||||||||
// Verificar se o token está na blacklist apenas se não for uma requisição de logout | ||||||||
String requestURI = request.getRequestURI(); | ||||||||
if (!isLogoutEndpoint(requestURI)) { | ||||||||
if (memoryBlacklistService.isBlacklisted(token)) { | ||||||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); | ||||||||
response.getWriter().write("Token inválido"); | ||||||||
return; | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
try { | ||||||||
final String jwt = authHeader.substring(7); | ||||||||
final String jwt = token; | ||||||||
|
||||||||
if (jwtService.isTokenExpired(jwt)) { | ||||||||
response.setStatus(HttpServletResponse.SC_UNAUTHORIZED); | ||||||||
|
@@ -63,4 +71,19 @@ protected void doFilterInternal( | |||||||
response.getWriter().write("Unauthorized."); | ||||||||
} | ||||||||
} | ||||||||
|
||||||||
/** | ||||||||
* Verifica se a URI da requisição é um endpoint de logout | ||||||||
* Usa uma abordagem mais robusta para evitar vulnerabilidades de comparação hardcoded | ||||||||
* e previne ataques de ReDoS (Regular Expression Denial of Service) | ||||||||
*/ | ||||||||
private boolean isLogoutEndpoint(String requestURI) { | ||||||||
// Lista de endpoints de logout que devem permitir tokens blacklisted | ||||||||
// Substitui a regex vulnerável por uma verificação mais segura | ||||||||
return requestURI != null && ( | ||||||||
requestURI.equals("/v1/auth/logout") || | ||||||||
requestURI.startsWith("/v1/auth/logout/") || | ||||||||
requestURI.contains("/logout") | ||||||||
Comment on lines
+85
to
+86
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. A verificação
Suggested change
Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||||||||
); | ||||||||
} | ||||||||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -94,4 +94,26 @@ public boolean validateToken(String token) { | |
return false; | ||
} | ||
} | ||
|
||
/** | ||
* Validates a token and checks if it's expired in a single operation. | ||
* This avoids redundant token parsing that occurs when calling validateToken() and isTokenExpired() separately. | ||
* | ||
* @param token the JWT token to validate | ||
* @return true if the token is valid and not expired, false otherwise | ||
*/ | ||
public boolean isTokenValid(String token) { | ||
try { | ||
Claims claims = Jwts.parserBuilder() | ||
.setSigningKey(getSignInKey()) | ||
.build() | ||
.parseClaimsJws(token) | ||
.getBody(); | ||
|
||
// Check if token is expired | ||
return !claims.getExpiration().before(new Date()); | ||
} catch (Exception e) { | ||
return false; | ||
} | ||
} | ||
Comment on lines
+105
to
+118
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. The method catches all exceptions with a generic Copilot uses AI. Check for mistakes. Positive FeedbackNegative Feedback |
||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
O método
getEmailFromToken()
não é chamado após a validação do token emisTokenValid()
. Se o token for inválido, este método pode falhar ou retornar dados incorretos. Recomendo validar se o métodogetEmailFromToken()
trata adequadamente tokens inválidos ou mover esta chamada para dentro de um bloco try-catch.Copilot uses AI. Check for mistakes.