Saltar al contenido

Pruebas unitarias de Spring Boot con JWT Token Security

Presta atención ya que en esta crónica encontrarás la contestación que buscas.

Solución:

Creo que resolví el problema (y espero no estar haciendo una mala práctica o creando una vulnerabilidad de seguridad en mi backend).

Seguí el consejo de @ punkrocker27ka y miré esta respuesta. En él dicen que están generando un token Oauth manualmente para las pruebas, así que decidí hacer lo mismo con mi token JWT.

Así que actualicé mi clase que genera los tokens JWT y los valida para que sean así:

public class TokenAuthenticationService 

    static final long EXPIRATIONTIME = 864_000_000; // 10 days
    static final String SECRET = "ThisIsASecret";
    static final String TOKEN_PREFIX = "Bearer";
    static final String HEADER_STRING = "Authorization";

    public static void addAuthentication(HttpServletResponse res, String username) 

        String jwt = createToken(username);

        res.addHeader(HEADER_STRING, TOKEN_PREFIX + " " + jwt);
    

    public static Authentication getAuthentication(HttpServletRequest request) 
        String token = request.getHeader(HEADER_STRING);
        if (token != null) 
            // parse the token.
            String user = Jwts.parser()
                    .setSigningKey(SECRET)
                    .parseClaimsJws(token.replace(TOKEN_PREFIX, ""))
                    .getBody()
                    .getSubject();

            return user != null ?
                    new UsernamePasswordAuthenticationToken(user, null, Collections.emptyList()) :
                        null;
        
        return null;
    

    public static String createToken(String username) 
        String jwt = Jwts.builder()
                .setSubject(username)
                .setExpiration(new Date(System.currentTimeMillis() + EXPIRATIONTIME))
                .signWith(SignatureAlgorithm.HS512, SECRET)
                .compact();

        return jwt;
    

Y luego creé una nueva prueba para ello:

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class TokenAuthenticationServiceTest 

    @Autowired
    private MockMvc mvc;

    @Test
    public void shouldNotAllowAccessToUnauthenticatedUsers() throws Exception 
        mvc.perform(MockMvcRequestBuilders.get("/test")).andExpect(status().isForbidden());
    

    @Test
    public void shouldGenerateAuthToken() throws Exception 
        String token = TokenAuthenticationService.createToken("john");

        assertNotNull(token);
        mvc.perform(MockMvcRequestBuilders.get("/test").header("Authorization", token)).andExpect(status().isOk());
    


Luego ejecuté las pruebas y pasaron, por lo que el token fue aceptado sin la necesidad de @WithMockUser anotación. Agregaré esto a mis otras clases de pruebas.

PD: el punto final de la prueba está por debajo.

/**
 * This controller is used only for testing purposes.
 * Especially to check if the JWT authentication is ok.
 */
@RestController
public class TestController 

    @RequestMapping(path = "/test", method = RequestMethod.GET)
    public String testEndpoint() 
        return "Hello World!";
    

Una cosa que debe tener en cuenta al probar con este método createToken () es que sus pruebas no pueden probar para un usuario inexistente.
Esto se debe a que createToken () solo crea un token JWT basado en el string pones en él.
Si desea asegurarse de que los usuarios inexistentes no puedan obtener acceso, le recomiendo hacer que su método createToken () sea privado y, en su lugar, use solicitudes para obtener el token, como este:

@Test
public void existentUserCanGetTokenAndAuthentication() throws Exception 
    String username = "existentuser";
    String password = "password";

    String body = ""username":"" + username + "", "password":" 
                  + password + """;

    MvcResult result = mvc.perform(MockMvcRequestBuilders.post("/v2/token")
            .content(body))
            .andExpect(status().isOk()).andReturn();

    String response = result.getResponse().getContentAsString();
    response = response.replace(""access_token": "", "");
    String token = response.replace(""", "");

    mvc.perform(MockMvcRequestBuilders.get("/test")
        .header("Authorization", "Bearer " + token))
        .andExpect(status().isOk());

De manera similar, puede mostrar que un usuario inexistente no podrá obtener este resultado:

@Test
public void nonexistentUserCannotGetToken() throws Exception 
    String username = "nonexistentuser";
    String password = "password";

    String body = ""username":"" + username + "", "password":" 
                  + password + """;

    mvc.perform(MockMvcRequestBuilders.post("/v2/token")
            .content(body))
            .andExpect(status().isForbidden()).andReturn();

Ten en cuenta comunicar esta crónica si si solucionó tu problema.

¡Haz clic para puntuar esta entrada!
(Votos: 0 Promedio: 0)



Utiliza Nuestro Buscador

Deja una respuesta

Tu dirección de correo electrónico no será publicada. Los campos obligatorios están marcados con *