Spring Security 5 で削除された SaltSource からの移行方法
Spring Framework / Spring Boot Advent Calendar 2017 19日めの記事になります
(参加登録数が少ないのですが、あともう少し参加できればと思っています!)
Spring Security 5.0.0.RELEASE が1ヶ月ほど前にリリースされました。
5.0.0.RC1 から、今まで Deprecated とされていた PasswordEncorder インタフェースがついに削除されています。
詳しい内容は公式のブログでRC1がリリースされたとき書かれています。
今回は、PasswordEncorder インタフェースと一緒に削除されている SaltSource インタフェースを利用していた場合のソルト値の解決方法になります。
解決方法
Spring Security 5 からの SaltSource を利用しないソルト値の解決方法について
4系の DaoAuthenticationProvider クラス などでは、外部からソルト値を指定できるように setSaltSource メソッド が用意されており、SaltSource インターフェースを実装したクラスを set することができていたのですが、SaltSource インターフェース自体が 5.0.0.RC1 から削除されています。
BcryptPasswordEncoder など内部でソルト値を生成するクラスを利用するように移行している方も多いと思いますが、5.0.0.RC1 からは、MessageDigestPasswordEncoder クラス を利用することで外部のソルト値を利用することができます。
クラスのコメントでも書かれていますが、 ソルト値を含めてパスワードとすることで、移行がほぼ完了します。
String salt = "jE5DjBxmsCLX5Y6KbdAYnlde26OEp7kP";
String rawPassword = "pPELAeMqks0orhLJ";
# sha256Password = sha256(パスワード + { + ソルト値 + })
String sha256Password = "8b10e647d273b7100e928e2d97330c392f57fcb2f4aa449e1e63e9b519023988";
String algorithm = "SHA-256";
String encodedPassword = "{" + algorithm + "}" + "{" + salt + "}" + sha256Password;
PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
if (passwordEncoder.matches(rawPassword, encodedPassword)) {
System.out.println("password is match!");
}
実際の動きを試されたい方は以下のように実行いただければと思います。
雛形となるプロジェクトを作成します。
# curl https://start.spring.io/starter.tgz -d dependencies=web,security -d bootVersion=2.0.0.M7 -d baseDir=demo | tar -xzvf -
雛形プロジェクト作成後、サンプルとして Controller クラスを作っていただき下記内容をコピペすることで動作を確認してください。
@ResponseBody
@RequestMapping(path="/sample", method=RequestMethod.GET, produces=MediaType.TEXT_PLAIN_VALUE)
public String sample() {
String rawPassword = "pPELAeMqks0orhLJ";
String encodedPassword = "{SHA-256}{jE5DjBxmsCLX5Y6KbdAYnlde26OEp7kP}8b10e647d273b7100e928e2d97330c392f57fcb2f4aa449e1e63e9b519023988";
PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
if (passwordEncoder.matches(rawPassword, encodedPassword)) {
return "password is match!";
}
return "password is missmatch!";
}
解説
- パスワードの先頭についている "{SHA-256}" について
パスワードとソルト値を足しただけではなく、"{SHA-256}" というのが頭についています。
これは、どの PasswordEncoder を利用するのか判定するための識別子になっています。
PasswordEncoderFactories クラスを見ていただくと、すでに SHA-256 の識別子で MessageDigestPasswordEncoder が登録されています。
よって、今回は接頭辞をつけるだけで利用する適切な PasswordEncoder が見つかります。
- 実際の移行について
実際の移行時には、UserDetailsService インターフェースを実装しているクラスのほうで パスワードを適切な形に合わせた User のインスタンスを作成してあげることで移行ができるかと思います。
いかがでしょうか。
あくまで4系から5に上げる移行時の対策としていただければと思います。
今回、Spring Fest 2017 で発表されていた Spring Security 5.0 解剖速報 を参考にさせていただきました。