fix(auth): drop @Authenticated/@RolesAllowed on cookie-based endpoints
CI / Build Native (push) Successful in 6m14s
CI / Build Native (push) Successful in 6m14s
Quarkus security solo lee JWT del header 'Authorization: Bearer ...'
por defecto. Esta app entrega el JWT en una cookie HttpOnly
('auth-token'), entonces @Authenticated/@RolesAllowed rebotaban con
401 antes de que el endpoint pudiera validar manualmente.
Reemplazos:
- @Authenticated en /change-password: sacada. El endpoint ya hace
jwtCookieAuth.extractToken() y devuelve 401 manual si falla.
- @Authenticated en /check: sacada. Endpoint ahora extrae y valida
el JWT a mano.
- @Authenticated en /me: never estuvo, OK.
- @RolesAllowed('admin') en /admin/reset-password y /admin/users:
reemplazada por chequeo manual jwt.getGroups().contains('admin'),
devolviendo 403 si no es admin.
Sigue funcionando el MustChangePasswordFilter porque sigue siendo
un ContainerRequestFilter con @Priority(AUTHENTICATION+100) y no
requiere auth previa para correr: simplemente aborta con 403 si
mustChangePassword=true salvo allowlist (change-password, logout).
Removida inyeccion no usada de currentJwt (JsonWebToken) que solo
estaba para @RolesAllowed.
This commit is contained in:
@@ -1,7 +1,5 @@
|
|||||||
package com.l2.shots.auth;
|
package com.l2.shots.auth;
|
||||||
|
|
||||||
import io.quarkus.security.Authenticated;
|
|
||||||
import jakarta.annotation.security.RolesAllowed;
|
|
||||||
import jakarta.inject.Inject;
|
import jakarta.inject.Inject;
|
||||||
import jakarta.ws.rs.Consumes;
|
import jakarta.ws.rs.Consumes;
|
||||||
import jakarta.ws.rs.GET;
|
import jakarta.ws.rs.GET;
|
||||||
@@ -19,6 +17,12 @@ import org.eclipse.microprofile.jwt.JsonWebToken;
|
|||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.UUID;
|
import java.util.UUID;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* No usa @Authenticated / @RolesAllowed porque Quarkus security por defecto
|
||||||
|
* solo lee el JWT del header "Authorization: Bearer ...". Esta app entrega
|
||||||
|
* el JWT en una cookie HttpOnly, asi que la validacion la hacemos a mano
|
||||||
|
* via JwtCookieAuth en cada endpoint que requiere auth.
|
||||||
|
*/
|
||||||
@Path("/api/auth")
|
@Path("/api/auth")
|
||||||
@Produces(MediaType.APPLICATION_JSON)
|
@Produces(MediaType.APPLICATION_JSON)
|
||||||
@Consumes(MediaType.APPLICATION_JSON)
|
@Consumes(MediaType.APPLICATION_JSON)
|
||||||
@@ -30,9 +34,6 @@ public class AuthResource {
|
|||||||
@Inject
|
@Inject
|
||||||
JwtCookieAuth jwtCookieAuth;
|
JwtCookieAuth jwtCookieAuth;
|
||||||
|
|
||||||
@Inject
|
|
||||||
JsonWebToken currentJwt;
|
|
||||||
|
|
||||||
@ConfigProperty(name = "app.auth.cookie-name")
|
@ConfigProperty(name = "app.auth.cookie-name")
|
||||||
String cookieName;
|
String cookieName;
|
||||||
|
|
||||||
@@ -81,7 +82,6 @@ public class AuthResource {
|
|||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Path("/change-password")
|
@Path("/change-password")
|
||||||
@Authenticated
|
|
||||||
public Response changePassword(@Context HttpHeaders headers, ChangePasswordRequest body) {
|
public Response changePassword(@Context HttpHeaders headers, ChangePasswordRequest body) {
|
||||||
if (body == null || body.currentPassword() == null || body.newPassword() == null) {
|
if (body == null || body.currentPassword() == null || body.newPassword() == null) {
|
||||||
return Response.status(400).entity(new ErrorBody("Faltan campos requeridos")).build();
|
return Response.status(400).entity(new ErrorBody("Faltan campos requeridos")).build();
|
||||||
@@ -114,14 +114,16 @@ public class AuthResource {
|
|||||||
|
|
||||||
@POST
|
@POST
|
||||||
@Path("/admin/reset-password")
|
@Path("/admin/reset-password")
|
||||||
@RolesAllowed("admin")
|
public Response adminResetPassword(@Context HttpHeaders headers, AdminResetPasswordRequest body) {
|
||||||
public Response adminResetPassword(AdminResetPasswordRequest body) {
|
|
||||||
if (body == null || body.username() == null || body.newPassword() == null) {
|
if (body == null || body.username() == null || body.newPassword() == null) {
|
||||||
return Response.status(400).entity(new ErrorBody("Faltan campos requeridos")).build();
|
return Response.status(400).entity(new ErrorBody("Faltan campos requeridos")).build();
|
||||||
}
|
}
|
||||||
|
Optional<JsonWebToken> jwt = jwtCookieAuth.extractToken(headers);
|
||||||
|
if (jwt.isEmpty()) return Response.status(401).build();
|
||||||
|
if (!jwt.get().getGroups().contains("admin")) return Response.status(403).build();
|
||||||
UUID requesterId;
|
UUID requesterId;
|
||||||
try {
|
try {
|
||||||
requesterId = UUID.fromString(currentJwt.getSubject());
|
requesterId = UUID.fromString(jwt.get().getSubject());
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
return Response.status(401).build();
|
return Response.status(401).build();
|
||||||
}
|
}
|
||||||
@@ -146,15 +148,17 @@ public class AuthResource {
|
|||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("/admin/users")
|
@Path("/admin/users")
|
||||||
@RolesAllowed("admin")
|
public Response adminListUsers(@Context HttpHeaders headers) {
|
||||||
public Response adminListUsers() {
|
Optional<JsonWebToken> jwt = jwtCookieAuth.extractToken(headers);
|
||||||
|
if (jwt.isEmpty()) return Response.status(401).build();
|
||||||
|
if (!jwt.get().getGroups().contains("admin")) return Response.status(403).build();
|
||||||
return Response.ok(authService.listUsersForAdmin()).build();
|
return Response.ok(authService.listUsersForAdmin()).build();
|
||||||
}
|
}
|
||||||
|
|
||||||
@GET
|
@GET
|
||||||
@Path("/check")
|
@Path("/check")
|
||||||
@Authenticated
|
public Response check(@Context HttpHeaders headers) {
|
||||||
public Response check() {
|
if (jwtCookieAuth.extractToken(headers).isEmpty()) return Response.status(401).build();
|
||||||
return Response.ok().build();
|
return Response.ok().build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user