DeviseからGoogle Identity Platformにユーザー移行できるか試してみた
Leaner Technologies で SaaS のプロダクトマネージャーをしているころちゃん(@corocn)です。
弊社のサービスは Rails で動いており、現状 Devise gem を利用しているのですが、新規サービスの立ち上げに伴い IDaaS or 自前の認証基盤への移行を検討しています。
今回は Google Identity Platform(以下、GIP)をターゲットとしたときに、パスワードハッシュをそのまま移行できるか試してみた記録です。 つまり、ユーザーの平文のパスワードを知らない状況で、ユーザーの手を煩わせず移行できるかを検証したいのです。
結論を先に述べると、移行できました。
方針
次のドキュメントをベースに検証しました。
getAuth()
.importUsers(
[
{
uid: 'some-uid',
email: 'user@example.com',
// Must be provided in a byte buffer.
passwordHash: Buffer.from('password-hash'),
// Must be provided in a byte buffer.
passwordSalt: Buffer.from('salt'),
},
],
{
hash: {
algorithm: 'HMAC_SHA256',
// Must be provided in a byte buffer.
key: Buffer.from('secret'),
},
}
)
このあたりのコードを見る感じ、インポート時にアルゴリズムを指定できそうですね。
Ruby のサンプルコードはなく、そもそも SDK がサポート対象外でした。Ruby から GIP にアクセスする場合は google-apis-identitytoolkit_v3 を使う方法がありますが、アルゴリズムの指定はできなさそうでした。
ということでドキュメントの最後にある Firebase CLI + CSV によるバルクインポートを試します。
Bcrypt
Devise は Bcrypt を採用しています。
Bcrypt はパスワードハッシュに Salt などが含まれる構造になっています。移行時もアルゴリズムの指定とパスワードハッシュを取り込むだけでよさそうです。
https://en.wikipedia.org/wiki/Bcrypt から引用。
準備1: テナントの作成
GIP のテナントを作成して、Email / Password でのログインを有効にしておきます。また、テスト用のユーザーを作成しておきます。テナントの作成には Google Cloud の課金の設定が必要です。
準備2: テスト用のアプリの作成
ログイン確認のために、テスト用のアプリを用意しておきます。
次のドキュメントが参考になります。
上記ドキュメントに沿って進めると、次のような index.html が出来上がります。
<html>
<body>
<div>Identity Platform Quickstart</div>
<div id="message">Loading...</div>
<script src="https://www.gstatic.com/firebasejs/8.0/firebase.js"></script>
<script>
var config = {
apiKey: "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
authDomain: "XXXXXXXXXX.firebaseapp.com",
};
firebase.initializeApp(config);
</script>
<script>
var email = "hoge@example.com";
var password = "mypassword";
firebase.auth().onAuthStateChanged(function (user) {
if (user) {
document.getElementById("message").innerHTML = "Welcome, " + user.email;
} else {
document.getElementById("message").innerHTML = "No user signed in.";
}
});
firebase.auth().signInWithEmailAndPassword(email, password).catch(function (error) {
document.getElementById("message").innerHTML = error.message;
});
</script>
</body>
</html>
apiKey、authDomain は準備 1 で作成したテナントの設定を反映します。 email、password はログインを試したいテストユーザーのものを一旦設定しておきましょう。
認証に成功すると次のような表示をブラウザで確認できます。
準備3: Firebase CLI のインストール
インポートには Firebase CLI を使うので予めインストールしておきます。
私はバージョンマネージャーとして asdf を利用しているので asdf-firebase を利用してインストールしましたが、手段はなんでもいいでしょう。
インストールしたらログインを済ませて、既存ユーザーのエクスポートができるか試してみます。
$ firebase login
$ firebase auth:export users.csv --project=your-project-name
出力された CSV を確認すると、サンプルで作成されたユーザーが出力されました。うまくいってそうですね。
インポート
インポート用の CSV のフォーマットは次のページに記載されています。
今回は 4 列しか記入していません。
パスワードハッシュは、Devise のパスワードハッシュ(encrypted_password フィールド)の値をそのまま記入するのではなく、base64 エンコードが必要です。
CSV が準備できたので、取り込んでみます。
$ firebase auth:import users.csv --hash-algo=BCRYPT --project=your-project-name
Processing users.csv (132 bytes)
Starting importing 1 account(s).
✔ Imported successfully.
取り込みが完了しました。
テスト用のアプリでログインを試みたところ、問題なくログインできました。
他IDaaSの対応状況
ちなみに Auth0 でも同様に移行できます。
Cognito はインポート用の CSV を見る限り未対応ですね。(勘違いだったらすいません。)
まとめ
Devise のパスワードハッシュを Google Identity Platform にインポートしてログインできることを検証しました。
基盤を移行したタイミングでユーザーにパスワード再設定を強いるのは体験が良くないですし、考慮しなきゃいけないことも増えます。IDaaS を使うのであれば、このあたりの便利な機能を活用していけると良さそうですね。
それでは。
宣伝
SaaS の認証基盤や権限管理について雑談したい人いましたらぜひ!
Discussion