備忘録。
セキュリティ要件の変更などにより、Spring Security の PasswordEncoder (エンコード方式) を移行したいケースがあるとする。
AbstractDaoAuthenticationConfigurer#passwordEncoder
を変更して DB に格納しているパスワードをマイグレーションするだけかと思ったけど、DB のパスワードはエンコードされているため機械的にマイグレーションするのは無理そう。
Spring Security 5.x 以降であればマイグレーションの仕組みがあるっぽいけど、今回は 4.x のときにどうするかという話。(バージョンアップできるならそれでよし)
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 { // 新しい PasswordEncoder (PBKDF2) でチェックする return super.matches(rawPassword, encodedPassword); } catch (IllegalArgumentException e) { // チェックNGの場合は旧の PasswordEncoder (bcrypt) でチェックする 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; } }
現場からは以上です。