Commit 72f0cf4d by Rubén Ramírez

feat: [TestServicioUsuario]: avances en la implementación del test de autenticación de usuario

parent 44deb578
package com.ujaen.tfg.mangaffinity.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
......
package com.ujaen.tfg.mangaffinity.excepciones;
public class UsuarioNoExiste extends RuntimeException {}
......@@ -28,6 +28,8 @@ public class RepositorioUsuario {
em.persist(usuario);
}
@Transactional(propagation = Propagation.SUPPORTS, readOnly = true)
public Optional<Usuario> findByEmail(String email) {
String query = "SELECT u FROM Usuario u WHERE u.email = :email";
......
......@@ -10,71 +10,48 @@ import javax.crypto.SecretKey;
@Component
public class JwtUtil {
// Clave secreta para firmar y verificar el token (debe ser la misma en todo el proyecto)
private static final SecretKey SECRET_KEY = Keys.secretKeyFor(SignatureAlgorithm.HS256);
private static final long EXPIRATION_TIME = 86400000; // 1 día en milisegundos
/**
* Genera un token JWT con los datos proporcionados.
*
* @param claims Información adicional a incluir en el token.
* @param subject Usuario o identificador asociado al token.
* @return Token JWT generado.
*/
// Genera un token JWT con los datos proporcionados
public String generateToken(Map<String, Object> claims, String subject) {
return Jwts.builder()
.setClaims(claims)
.setSubject(subject)
.setIssuedAt(new Date(System.currentTimeMillis()))
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME))
.signWith(SECRET_KEY)
.setIssuedAt(new Date()) // Fecha de emisión
.setExpiration(new Date(System.currentTimeMillis() + EXPIRATION_TIME)) // Expiración del token
.signWith(SECRET_KEY) // Firmar el token con la misma clave
.compact();
}
/**
* Obtiene el usuario (subject) desde un token JWT.
*
* @param token Token JWT.
* @return Usuario extraído del token.
*/
// Decodifica el JWT utilizando la misma clave secreta
public Claims decodeJWT(String token) {
return Jwts.parserBuilder()
.setSigningKey(SECRET_KEY) // Usamos la misma clave para decodificar
.build()
.parseClaimsJws(token)
.getBody();
}
// Extrae el nombre de usuario (subject) desde el token JWT
public String extractUsername(String token) {
return extractClaim(token, Claims::getSubject);
}
/**
* Obtiene la fecha de expiración de un token JWT.
*
* @param token Token JWT.
* @return Fecha de expiración.
*/
// Extrae la fecha de expiración del token
public Date extractExpiration(String token) {
return extractClaim(token, Claims::getExpiration);
}
public String extractRoles(String token) {
Claims claims = extractAllClaims(token);
return (String) claims.get("roles"); // Extrae el rol desde los claims
}
/**
* Extrae un claim específico del token.
*
* @param token Token JWT.
* @param claimsResolver Función que extrae el claim.
* @return Valor del claim extraído.
*/
// Extrae un claim específico del token
public <T> T extractClaim(String token, java.util.function.Function<Claims, T> claimsResolver) {
final Claims claims = extractAllClaims(token);
return claimsResolver.apply(claims);
}
/**
* Valida si un token es correcto y no ha expirado.
*
* @param token Token JWT.
* @param username Nombre de usuario a validar.
* @return `true` si el token es válido.
*/
// Validar si un token es correcto y no ha expirado
public boolean validateToken(String token, String username) {
final String extractedUsername = extractUsername(token);
return (extractedUsername.equals(username) && !isTokenExpired(token));
......@@ -86,7 +63,7 @@ public class JwtUtil {
private Claims extractAllClaims(String token) {
return Jwts.parserBuilder()
.setSigningKey(SECRET_KEY)
.setSigningKey(SECRET_KEY) // Usamos la misma clave para extraer los claims
.build()
.parseClaimsJws(token)
.getBody();
......
package com.ujaen.tfg.mangaffinity.servicios;
import com.ujaen.tfg.mangaffinity.entidades.Usuario;
import com.ujaen.tfg.mangaffinity.excepciones.UsuarioNoExiste;
import com.ujaen.tfg.mangaffinity.repositorios.RepositorioUsuario;
import com.ujaen.tfg.mangaffinity.rest.DTO.DTOLoginRespuesta;
import com.ujaen.tfg.mangaffinity.rest.DTO.DTOUsuario;
......@@ -22,21 +23,22 @@ public class ServicioUsuarios {
RepositorioUsuario repositorioUsuario;
@Autowired
private static final PasswordEncoder passwordEncoder = new BCryptPasswordEncoder();
private PasswordEncoder passwordEncoder;
@Autowired
private JwtUtil jwtUtil;
private static final Usuario admin;
private final Usuario admin;
static {
// Se crea el admin con la contraseña encriptada
admin = new Usuario();
admin.setEmail("admin@example.com");
admin.setNombreUsuario("admin");
admin.setContrasenia(passwordEncoder.encode("adminpassword")); // Contraseña encriptada
public ServicioUsuarios() {
this.admin = new Usuario();
this.admin.setEmail("admin@example.com");
this.admin.setNombreUsuario("admin");
}
/**
* Función para crear un Socio en la estructura
* @param usuario usuario que se va a añadir
......@@ -53,15 +55,35 @@ public class ServicioUsuarios {
* @return DTOLoginRespuesta con el token si es válido, o null si falla
*/
public DTOLoginRespuesta autenticarUsuario(String email, String contrasenia) {
System.out.println("🔍 Intentando autenticar usuario: " + email);
Optional<Usuario> usuario = repositorioUsuario.findByEmail(email);
if (usuario.isEmpty() || !passwordEncoder.matches(contrasenia, usuario.get().getContrasenia())) {
// Si el usuario no existe o la contraseña no es válida
if (usuario.isEmpty()) {
System.out.println("❌ Usuario no encontrado: " + email);
return null;
}
// Verificamos si el usuario es el "admin"
String rol = (email.equals(admin.getEmail())) ? "ADMIN" : "USUARIO_REGISTRADO";
System.out.println("✅ Usuario encontrado: " + usuario.get().getEmail());
System.out.println("Contraseña almacenada (encriptada): " + usuario.get().getContrasenia());
System.out.println("Contraseña ingresada: " + contrasenia);
System.out.println("¿Coincide? " + passwordEncoder.matches(contrasenia, usuario.get().getContrasenia()));
if (!passwordEncoder.matches(contrasenia, usuario.get().getContrasenia())) {
System.out.println("❌ Contraseña incorrecta para: " + email);
return null;
}
String rol = "USUARIO_REGISTRADO";
if (email.equals(admin.getEmail())) {
if (!passwordEncoder.matches(contrasenia, passwordEncoder.encode("adminpassword"))) {
System.out.println("❌ Contraseña incorrecta para admin");
return null;
}
rol = "ADMIN";
}
// Datos adicionales en el token (claims)
Map<String, Object> claims = new HashMap<>();
......@@ -72,8 +94,21 @@ public class ServicioUsuarios {
// Generamos el token JWT
String token = jwtUtil.generateToken(claims, usuario.get().getEmail());
System.out.println("✅ Usuario autenticado exitosamente. Token generado.");
return new DTOLoginRespuesta(token, usuario.get().getEmail(), usuario.get().getContrasenia());
}
public Usuario buscaUsuario(String email){
if (email.equals(admin.getEmail()))
return admin;
Optional<Usuario> usuario = repositorioUsuario.findByEmail(email);
if(usuario.isPresent())
return usuario.get();
throw new UsuarioNoExiste();
}
}
......@@ -5,85 +5,97 @@ import com.ujaen.tfg.mangaffinity.config.JpaTestConfig;
import com.ujaen.tfg.mangaffinity.entidades.Usuario;
import com.ujaen.tfg.mangaffinity.excepciones.UsuarioYaRegistrado;
import com.ujaen.tfg.mangaffinity.rest.DTO.DTOLoginRespuesta;
import com.ujaen.tfg.mangaffinity.seguridad.JwtUtil;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
import org.assertj.core.api.Assertions;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.annotation.DirtiesContext;
import org.springframework.test.context.ActiveProfiles;
import javax.crypto.SecretKey;
import java.nio.charset.StandardCharsets;
import java.security.Key;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
@SpringBootTest(classes = {MangAffinityApplication.class, JpaTestConfig.class})
@ActiveProfiles("test")
public class TestServicioUsuarios {
@Autowired
ServicioUsuarios servicioUsuarios;
@Autowired
private PasswordEncoder passwordEncoder;
@Autowired
JwtUtil jwtUtil;
private static final Logger logger = LoggerFactory.getLogger(TestServicioUsuarios.class);
private static final SecretKey key = Keys.secretKeyFor(SignatureAlgorithm.HS256); // Clave de 256 bits
private Claims decodeJWT(String token) {
return Jwts.parserBuilder()
.setSigningKey(key) // Usando la misma clave
.build()
.parseClaimsJws(token)
.getBody();
}
@Test
@DirtiesContext
void testCrearSocio(){
var usuario1 = new Usuario("pedro@gmail.com", "Pedro", "pedrito");
// Comprobamos que no se pueda meter dos socios con el mismo email
var usuario1 = new Usuario("pedro@gmail.com", "Pedro", "pedrito"); // Se pasa en texto plano
servicioUsuarios.crearUsuario(usuario1);
assertThatThrownBy(() -> servicioUsuarios.crearUsuario(usuario1)).isInstanceOf(UsuarioYaRegistrado.class);
}
/**
@Test
@DirtiesContext
void testAutenticacionUsuario() {
// Caso 1: Registrar un usuario en la base de datos en memoria
Usuario usuario = new Usuario("test@example.com", "Test User", "password123");
servicioUsuarios.crearUsuario(usuario);
void testAutenticarUsuario() {
logger.info("🔍 Iniciando test de autenticación");
// Caso 2: Intentar autenticar al usuario
DTOLoginRespuesta respuesta = servicioUsuarios.autenticarUsuario("test@example.com", "password123");
// Caso 1: Usuario con email incorrecto
String emailInexistente = "nonexistent@example.com";
String contraseniaValida = "validpassword";
assertThat(servicioUsuarios.autenticarUsuario(emailInexistente, contraseniaValida)).isNull();
logger.info("✅ Caso 1 completado: Usuario inexistente no autenticado");
// Verificar que se ha generado un token
Assertions.assertThat(respuesta).isNotNull();
Assertions.assertThat(respuesta.getToken()).isNotNull();
// Caso 2: Contraseña incorrecta
String emailExistente = "test@example.com";
String contraseniaIncorrecta = "wrongpassword";
assertThat(servicioUsuarios.autenticarUsuario(emailExistente, contraseniaIncorrecta)).isNull();
logger.info("✅ Caso 2 completado: Contraseña incorrecta no autenticada");
// Caso 3: Intentar autenticar con una contraseña incorrecta
DTOLoginRespuesta respuestaIncorrecta = servicioUsuarios.autenticarUsuario("test@example.com", "wrongpassword");
// Caso 3: Usuario con email y contraseña correctos
var usuario1 = new Usuario("pedro@gmail.com", "Pedro", "pedrito"); // Se pasa en texto plano
servicioUsuarios.crearUsuario(usuario1);
// Verificar que no se ha generado un token
Assertions.assertThat(respuestaIncorrecta).isNull();
}
Usuario usuarioGuardado = servicioUsuarios.buscaUsuario("pedro@gmail.com");
assertThat(usuarioGuardado).isNotNull();
logger.info("✅ Usuario guardado en BD: {}", usuarioGuardado.getEmail());
logger.info("Contraseña en BD (encriptada): {}", usuarioGuardado.getContrasenia());
**/
@Test
@DirtiesContext
void testAutenticarUsuario() {
// Caso 1: Usuario con email incorrecto
String emailInexistente = "nonexistent@example.com";
String contraseniaValida = "validpassword";
assertThat(servicioUsuarios.autenticarUsuario(emailInexistente, contraseniaValida)).isNull();
// Caso 2: Contraseña incorrecta
String emailExistente = "test@example.com"; // Este email debe existir en tu base de datos de prueba
String contraseniaIncorrecta = "wrongpassword";
assertThat(servicioUsuarios.autenticarUsuario(emailExistente, contraseniaIncorrecta)).isNull();
// Caso 3: Usuario con email y contraseña correctos
String emailCorrecto = "test@example.com"; // Este email debe existir en tu base de datos de prueba
String contraseniaCorrecta = "validpassword"; // La contraseña debe ser la correcta
DTOLoginRespuesta respuestaValida = servicioUsuarios.autenticarUsuario(emailCorrecto, contraseniaCorrecta);
assertThat(respuestaValida).isNotNull();
assertThat(respuestaValida.getToken()).isNotNull();
// Comprobamos que el rol de usuario registrado esté incluido en el token
assertThat(respuestaValida.getToken()).contains("rol", "USUARIO_REGISTRADO");
// Caso 4: Usuario ADMIN con email correcto
String emailAdmin = "admin@example.com"; // Este debe ser el email del admin
String contraseniaAdmin = "adminpassword"; // Contraseña encriptada para el admin
DTOLoginRespuesta respuestaAdmin = servicioUsuarios.autenticarUsuario(emailAdmin, contraseniaAdmin);
assertThat(respuestaAdmin).isNotNull();
assertThat(respuestaAdmin.getToken()).isNotNull();
// Comprobamos que el rol ADMIN esté presente en el token
assertThat(respuestaAdmin.getToken()).contains("rol", "ADMIN");
}
}
DTOLoginRespuesta respuestaValida = servicioUsuarios.autenticarUsuario(usuario1.getEmail(), "pedrito");
assertThat(respuestaValida).isNotNull();
assertThat(respuestaValida.getToken()).isNotNull();
logger.info("✅ Caso 3 completado: Usuario autenticado correctamente");
// Comprobamos que el rol de usuario registrado esté incluido en el token
Claims claims = jwtUtil.decodeJWT(respuestaValida.getToken()); // Usamos la misma clave secreta para decodificar
assertThat(claims.get("rol")).isEqualTo("USUARIO_REGISTRADO");
logger.info("✅ El rol de usuario registrado está presente en el token");
}
}
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or sign in to comment