1. Información general
En Spring Security 4, era posible almacenar contraseñas en texto sin formato utilizando autenticación en memoria.
Una importante revisión del proceso de administración de contraseñas en la versión 5 ha introducido un mecanismo predeterminado más seguro para codificar y decodificar contraseñas. Esto significa que si su aplicación Spring almacena las contraseñas en texto sin formato, la actualización a Spring Security 5 puede causar problemas.
En este breve tutorial, describiremos uno de esos problemas potenciales y demostraremos una solución.
2. Spring Security 4
Comenzaremos mostrando una configuración de seguridad estándar que proporciona autenticación simple en memoria (válida para Spring 4):
@Configuration public class InMemoryAuthWebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("spring") .password("secret") .roles("USER"); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/private/**") .authenticated() .antMatchers("/public/**") .permitAll() .and() .httpBasic(); } }
Esta configuración define la autenticación para todos los métodos / privados / asignados y el acceso público para todo lo que se encuentre en / public /.
Si usamos la misma configuración en Spring Security 5, obtendremos el siguiente error:
java.lang.IllegalArgumentException: There is no PasswordEncoder mapped for the id "null"
El error nos dice que la contraseña dada no se pudo decodificar ya que no se configuró ningún codificador de contraseña para nuestra autenticación en memoria .
3. Spring Security 5
Podemos corregir este error definiendo un PasswordEncoder de delegación con la clase PasswordEncoderFactories .
Usamos este codificador para configurar nuestro usuario con el AuthenticationManagerBuilder:
@Configuration public class InMemoryAuthWebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { PasswordEncoder encoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); auth.inMemoryAuthentication() .withUser("spring") .password(encoder.encode("secret")) .roles("USER"); } }
Ahora, con esta configuración, estamos almacenando nuestra contraseña en memoria usando BCrypt en el siguiente formato:
{bcrypt}$2a$10$MF7hYnWLeLT66gNccBgxaONZHbrSMjlUofkp50sSpBw2PJjUqU.zS
Aunque podemos definir nuestro propio conjunto de codificadores de contraseña, se recomienda seguir con los codificadores predeterminados proporcionados en PasswordEncoderFactories .
3.2. NoOpPasswordEncoder
Si por alguna razón no queremos codificar la contraseña configurada, podemos hacer uso de NoOpPasswordEncoder .
Para hacerlo, simplemente prefijamos la frase de contraseña que proporcionamos al método password () con el identificador {noop} :
@Configuration public class InMemoryNoOpAuthWebSecurityConfigurer extends WebSecurityConfigurerAdapter { @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.inMemoryAuthentication() .withUser("spring") .password("{noop}secret") .roles("USER"); } }
De esta manera, Spring Security usará NoOpPasswordEncoder debajo del capó cuando compare la contraseña proporcionada por el usuario con la que configuramos anteriormente.
Sin embargo, tenga en cuenta que nunca deberíamos utilizar este enfoque en la aplicación de producción. Como dice la documentación oficial, NoOpPasswordEncoder se ha desaprobado para indicar que es una implementación heredada y su uso se considera inseguro .
3.3. Migrar contraseñas existentes
Podemos actualizar las contraseñas existentes a los estándares recomendados de Spring Security 5 mediante:
- Actualización de contraseñas almacenadas en texto sin formato con su valor codificado:
String encoded = new BCryptPasswordEncoder().encode(plainTextPassword);
- Prefijar contraseñas almacenadas con hash con su identificador de codificador conocido:
{bcrypt}$2a$10$MF7hYnWLeLT66gNccBgxaONZHbrSMjlUofkp50sSpBw2PJjUqU.zS {sha256}97cde38028ad898ebc02e690819fa220e88c62e0699403e94fff291cfffaf8410849f27605abcbc0
- Solicitar a los usuarios que actualicen sus contraseñas cuando se desconoce el mecanismo de codificación de las contraseñas almacenadas
4. Conclusión
En este ejemplo rápido, actualizamos una configuración de autenticación en memoria de Spring 4 válida a Spring 5 usando el nuevo mecanismo de almacenamiento de contraseña.
Como siempre, puede encontrar el código fuente en el proyecto GitHub.