備忘録。
セキュリティ要件の変更などにより、Spring Security の PasswordEncoder (エンコード方式) を移行したいケースがあるとする。
AbstractDaoAuthenticationConfigurer#passwordEncoder
を変更して DB に格納しているパスワードをマイグレーションするだけかと思ったけど、DB のパスワードはエンコードされているため機械的にマイグレーションするのは無理そう。
Spring Security 5.x 以降であればマイグレーションの仕組みがあるっぽいけど、今回は 4.x のときにどうするかという話。(バージョンアップできるならそれでよし)
docs.spring.io
Migrating PasswordEncoder
2段階でパスワードをチェックする encoder を自作する。ここでは、BCryptPasswordEncoder
から Pbkdf2PasswordEncoder
に移行する例。
@Component
public class MigratingPasswordEncoder extends Pbkdf2PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
return super.encode(rawPassword);
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
try {
return super.matches(rawPassword, encodedPassword);
} catch (IllegalArgumentException e) {
return new BCryptPasswordEncoder().matches(rawPassword, encodedPassword);
}
}
}
これを AbstractDaoAuthenticationConfigurer#passwordEncoder
に設定する。あとは、アカウント作成やパスワード変更の際に PBKDF2 でエンコードして DB に格納できるようにすれば、旧方式の既存パスワードを段階的に移行できるはず。
旧方式のときにパスワード変更を強制したい
AuthenticationSuccessHandler#onAuthenticationSuccess
で、どちらの方式でエンコードされているか判定して、旧方式の場合はパスワード変更画面に飛ばすとかで対応できそう。ただし、旧方式のパスワードかどうかを判定できることが前提。
bcrypt から PBKDF2 の移行なら以下で判定できる。(bcrypt でエンコードした値は先頭が $2a$
で始まるため)
public boolean upgradeEncoding(String encoded) {
try {
Hex.decode(encoded);
return false;
} catch (Exception e) {
return true;
}
}
現場からは以上です。