Tengo un formulario de inicio de sesión con autenticación de Spring Security jdbc, funciona bien con el envío normal de formularios.

Ahora he cifrado la contraseña del usuario en el lado del cliente con javascript, uso cryptoJs y la contraseña cifrada se envía al servidor, el problema es que tengo que decodificar la contraseña antes de dejar que Spring compruebe el hash de la contraseña en el base de datos y no puedo entender cómo hacerlo, lo he intentado con un filtro personalizado

public class LoginFilter extends UsernamePasswordAuthenticationFilter{

    public LoginFilter(AuthenticationManager auth){
        super.setAuthenticationManager(auth);
    }

    @Override
    public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response) throws AuthenticationException{
        //Decode password
        return super.attemptAuthentication(request, response);
    } 

}

Intercepta la solicitud, puedo obtener la contraseña y decodificarla, pero no puedo pasarla a UsernamePasswordAuthenticationFilter, ¿cómo puedo pasar a saltar la contraseña decodificada en lugar de la codificada enviada por el usuario? PD No estoy usando Https y sé que el cifrado de JavaScript probablemente sea inútil

1
Frenk 20 dic. 2019 a las 22:39

2 respuestas

La mejor respuesta

He encontrado una solución, no estoy seguro de si es la mejor posible, pero funciona, Spring usa un objeto PasswordEncoder para verificar que la contraseña escrita por el usuario coincida con la contraseña almacenada (y hash).

Estaba usando un BCryptPasswordEncoder que usa el método matches(rawPass,encodedPass) para verificar la contraseña, así que he creado mi propio PasswordEncoder de esta manera

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.jdbcAuthentication()
    .usersByUsernameQuery(USER_QUERY)
    .authoritiesByUsernameQuery(ROLE_QUERY)
    .dataSource(dataSource)
    .passwordEncoder(new PasswordEncoder(){

        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();

        @Override
        public boolean matches(CharSequence rawPassword, String encodedPassword) {

            // Decoding stuff on the encrypted password sended by the client (rawPassword)

            return encoder.matches(decryptedPassword, encodedPassword);
        }

        @Override
        public String encode(CharSequence rawPassword) {
            //Same crypto operation to get the plain password
            return encoder.encode(decryptedPassword);
        }
    });
} 

Para que el cliente envíe la contraseña cifrada al servidor, la PasswordEncoder personalizada la descifra para recuperar la contraseña simple y luego la pasa a la BCryptPasswordEncoder, Spring Security se encargará del resto del proceso de autenticación

0
Frenk 23 dic. 2019 a las 14:06

Sí, ideológicamente es realmente comprensible: si recibe una contraseña encriptada, para que pueda obtener y almacenar un hash de contraseña, y luego verificarlo (creo que ningún marco almacena y compara contraseñas reales, solo sus hashes). Pero este es tu propio problema y lo resolverás desde tu lado ...

Realmente, no puede establecer parámetros de solicitud en ningún lugar, pero puede establecer un nuevo atributo de solicitud y en cualquier lugar para obtenerlo de la solicitud: request.setAttribute("<string key>", <object value>); y var value = (String) request.getAttribute("<string key>");

0
Dmitry Ionash 20 dic. 2019 a las 21:57