MAGAZINE

ルーターマガジン

クローリング/スクレイピング

コマンドライン上で2要素認証のコードを取得しログインを自動化する

2025.10.10
Pocket

はじめに

近年、国内でも不正アクセスによる事件が相次ぎ、私たちが利用している多くのサービスで「二段階認証」の導入がほぼ必須となっています。 その中でも代表的なのが、Google Authenticatorを使ったワンタイムパスワード方式です。

本記事では、そのワンタイムパスワードをコマンドラインから取得し、最終的に自動化するまでの手順をまとめて紹介します。

Google Authenticator

二段階認証を提供するためのモバイルアプリケーションは複数ありますが、今回はGoogle Authenticatorを利用します。
登録したアカウントに紐づくワンタイムパスワードを生成し、それを30秒ごとに更新する機能を持っています。
複数のアカウントを同時に管理することができ、新規のアカウントを追加する際には、QRコードをスキャンすることで簡単にセットアップできます。
さらに以下のようなChrome拡張を用いることで、登録したアカウントのワンタイムパスワードをブラウザ上で表示することが可能です。
https://chromewebstore.google.com/detail/authenticator/bhghoamapcdpbohphigoooaddinpkbai?hl=ja

ワンタイムパスワードをCLIから取得する方法

まずは先程のChrome拡張アプリを用いて確認していたワンタイムパスワードをCLIから取得できるようにします。
手順は以下の通りです。

  1. oathtoolをインストール
    1. sudo apt install oathtool
  2. Google Authenticatorからシークレットキーを入手(方法は後述)
    1. 例:0123456789ABCDEFGHIJKLMNOPQRSTUV
  3. コマンドライン上で oathtool --totp -b “SECRET_KEY” を実行

ここで、Google Authenticatorからシークレットキーを入手する手順は以下の通りです。

  1. Chrome拡張のAuthenticatorを開き、左上の歯車アイコンからメニューを開く
    1. 事前にAuthenticatorにログインに使うアカウントを登録しておく
  2. メニューから「バックアップ」を選択
  3. 「バックアップファイルのダウンロード」を選択しテキストファイルをダウンロードする
  4. ダウンロードしたauthenticator.txtの中身を確認する。
    secretパラメータの値がシークレットキーとなっている。

Tableauへのログインを自動化

今回は「Tableau」を例に自動化をしてみます。

サンプルプログラム(tableau_login.rb)

以下のコマンドで実行してください。rubyファイルと.envファイルが同じ階層にあることを確認してください。

require 'chrome_remote'
require 'dotenv'

# 2段階認証コードをCLIから取得
def fetch_otp(secret_key)
  otp = `oathtool --totp -b #{secret_key}`.strip
  puts "One-time password: #{otp}"
  otp
end

# Chrome のリモートデバッグポートを指定してクライアントを作成
def launch_chrome
  # 事前に何らかのuser-data-dirを指定してChromeを起動しておき、初期設定を済ませておく必要がある
  IO.popen("google-chrome --remote-debugging-port=9222 --user-data-dir=./tmp/chrome_temp_dir")
  # Chromeが起動するまで待機
  sleep 2 until TCPSocket.new('localhost', 9222) rescue sleep 1
end

# クライアントを作成、自動操作を有効化
def create_client
  @client = ChromeRemote.client
  @client.send_cmd('Runtime.enable')
  @client.send_cmd('Page.enable')
end

# 必要な要素がロードされるまで待機する
def wait_for_page_load(client, selectors)
  expression = selectors.map { |selector| "!!document.querySelector('#{selector}')" }.join(' && ')
  loop do
    result = client.send_cmd('Runtime.evaluate', expression: expression)
    break if result['result']['value']
    sleep 0.5
  end
end

# ログインページの操作
def manipulate_login_page(email)
  @client.send_cmd('Page.navigate', url: 'https://sso.online.tableau.com/public/login')
  wait_for_page_load(@client, ['#email', '#login-submit'])
  @client.send_cmd('Runtime.evaluate', expression: <<-JS)
    document.querySelector('#email').value = '#{email}';
    document.querySelector('#login-submit').click();
  JS
end

# サイトURIの入力ページの操作
def manipulate_site_uri_page(site_uri)
  wait_for_page_load(@client, ['#site-uri', '#verify-button'])
  @client.send_cmd('Runtime.evaluate', expression: <<-JS)
    document.querySelector('#site-uri').value = '#{site_uri}';
    document.querySelector('#site-uri').dispatchEvent(new Event('input', { bubbles: true }));
    document.querySelector('#verify-button').disabled = false;
    document.querySelector('#verify-button').click();
  JS
end

# パスワードの入力ページの操作
def manipulate_password_page(password)
  wait_for_page_load(@client, ['#password', '#signInButton'])
  @client.send_cmd('Runtime.evaluate', expression: <<-JS)
    document.querySelector('#password').value = '#{password}';
    document.querySelector('#signInButton').click();
  JS
end

# 2段階認証コードの入力ページを操作
def manipulate_otp_page(secret_key)
  wait_for_page_load(@client, ['#root'])
  otp = fetch_otp(secret_key)
  @client.send_cmd('Runtime.evaluate', expression: <<-JS)
    document.querySelector('#root').querySelector('#input-9').value = '#{otp}';
    document.querySelector('#root').querySelector('button.slds-button_brand[type="submit"]').click();
  JS
end

# エントリーポイント
if __FILE__ == $PROGRAM_NAME
  # .envファイルから環境変数をロード
  Dotenv.load('.env')
  launch_chrome
  create_client
  manipulate_login_page(ENV['TABLEAU_EMAIL'])
  manipulate_site_uri_page(ENV['TABLEAU_SITE_URI'])
  manipulate_password_page(ENV['TABLEAU_PASSWORD'])
  manipulate_otp_page(ENV['TABLEAU_2FA_SECRET_KEY'])
  puts "Login process completed."
end

chrome_remoteを用いてGoogle Chromeを自動操縦し、ログインプロセスを自動化するという流れです。
実行の方法を説明します。まず、以下を参考にしてrubyプログラムと同じ階層に.envファイルを用意してください。

TABLEAU_2FA_SECRET_KEY = '0123456789ABCDEFGHIJKLMNPQRSTUV'
TABLEAU_EMAIL = 'sample@sample.com'
TABLEAU_PASSWORD = 'samplePassword'
TABLEAU_SITE_URI = 'sampleSite'

各変数の意味は以下の通りです。皆様の環境に合わせて適宜設定してください。

  • TABLEAU_2FA_SECRET_KEY:シークレットキー
  • TABLEAU_EMAIL:ログインに用いるEメールアドレス
  • TABLEAU_PASSWORD:ログインに用いるパスワード
  • TABLEAU_SITE_URI:Tableau CloudのサイトURI

Gemfile

上記のRubyプログラムでは外部ライブラリを利用しています。
そのため、以下のようなGemfileを用意してください。

source 'https://rubygems.org'

gem 'chrome_remote'
gem 'dotenv'

Rubyプログラムの実行前に以下のコマンドを実行してください。
bundle install

実行方法

用意ができたら、以下のコマンドでコードを実行してください。実行が終わると、Tableauへのログインが完了した状態となります。
bundle exec ruby tableau_login.rb

まとめ

今回はコマンドライン上でワンタイムパスワードを取得し、ログインを自動化するサンプルをご紹介しました。 弊社では、このような複雑なログイン作業も自動化することが可能です。 自動化でお困りの際はぜひご相談ください。

Pocket

CONTACT

お問い合わせ・ご依頼はこちらから