Playwrightで2FA(二要素認証)が必要なサイトをテストする

2FA: two-factor authentication = 二要素認証/2要素認証

この記事では以下、2FAで記載する。

E2Eとセキュア問題

E2Eテストするサイトがログインが必要かつ2FAが必須というサイトが当たり前になりつつある。

で、E2Eテストするときにヘッドレスブラウザ上で当然ログインする必要があるわけなのだけど、2FAをどうすればいいかという問題がある。

公式ガイドの認証情報取り回し方法を見る

認証情報を全テストで共有する方法と、どう扱うかというガイドがある。

Authentication | Playwright

詳細は読んでもらうとして、ざっくり見ると

mkdir -p playwright/.auth
echo "\nplaywright/.auth" >> .gitignore

まずこうして、センシティブ情報をコミットしないようにして、

const authFile = 'playwright/.auth/user.json';
await page.context().storageState({ path: authFile });

Playwrightで必要な操作を走らせたあとにファイルに書き出して、

{
      name: 'chromium',
      use: {
        ...devices['Desktop Chrome'],
        // Use prepared auth state.
        storageState: 'playwright/.auth/user.json',
      },
}

あとはconfigに挿し込むとOKという具合。

でも 2023-02-26現在、2FAに関する記述はない

解決方法は2択

ランタイムでTOTP生成して解決する方法

こういった同じ問題に取り組んでいるブログがある。

これらブログの内容は、普通に setup 処理として「シナリオ内でTOTPを生成して普通に2FA突破する」という方法。

わかる。

Pros

  • 完全にprogrammaticallyに2FA突破してE2Eできる
  • 2FAの動作自体をテストしたい場合はこの方法で完全に再現できる

Cons

  • パスワードとTOTPのシークレットをenvなりsecretmanager的なセキュアな場所に置いておく必要がある
  • TOTPのQRコードを1度生成済みだと無理(生成済みsecretを何回もREADできるサービスを自分は見たことがない)
    • E2E用システムユーザーを用意できるのなら問題ない

1度だけ人力で2FAする

もう一つは自分で1回だけPlaywrightのheadedモード(実際にchromiumブラウザが起動する)で普通にログイン作業をして2FAを突破しておく、という方法。

例えば GitHubにログインする場合。

playwright codegen https://github.com/login --save-storage playwright/.auth/user.json

codegenモードで起動してポチポチログイン作業する。 --save-storage しているのでセッションが書き出される。

ためしに確認のために --load-storage すると、ちゃんとログイン後の画面になることがわかる。

playwright codegen https://github.com/login --load-storage playwright/.auth/user.json",

ログイン状態のトップページが表示されている

Pros

  • ローカルでE2Eを走らせればOKというときにセットアップがラク
  • ローカルの.envとかにパスワードとOTPシークレットを置かなくてよい
  • 個人あるいは既存のすでにTOTP設定済みアカウントを使い回せる
    • E2E用のシステムユーザーを用意できない場合でもなんとかなる

Cons

  • 完全にprogrammaticallyではない
  • CIで動かしたいときに面倒
    • とはいえ playwright/.auth/user.json をセキュアに取り扱えばOK(TOTP生成の方式でも同じセンシティブ情報置き場問題はある)
  • 2FAの画面の2FAの実装自体をテストしたい場合はE2Eできてないのでダメ

どっちの作戦で行くかはケースバイケースだと思う。

どっちも認証情報は playwright/.auth/user.json に置いてPlaywrightに食べさせるので、テスト対象や認証フローやセンシティブ情報の置き場所やセットアップのラクさで選べばいい気がしている。