WebDriver(ChromeDriver)でProxyのWeb認証を通す

この記事は、Infocom Advent Calendar 2019 2日目の記事です。

qiita.com

経緯

社内からインターネットの何かを使うときにはProxyを通さなければならないのですが、現在のProxyは認証を通す必要があります。
Windowsで社内のADに参加している場合は、ログオン時に自動的に認証を通してくれるので意識する必要はありません。
ADに入っていない場合は、以下の条件を満たす必要があります。

  • httpのサイトにアクセスする
  • リダイレクトされた認証ページを開く
  • ユーザIDとパスワードを入力し、認証が通ったら最初に開いたhttpにリダイレクトされる

GUIが使えないLinux系のサーバではcurlを使ってプロキシ認証を通しています。
ところが、最近エラーになることが多くなってきました。
w3mでやったら一発でうまくいくのですが・・・
しばらくはコマンドを何度も実行するようにしていましたが、ある時WebDriverならうまくいくかもと思って試してみました。

結論から言うとうまくいってます!

ブラウザなら失敗したこと無いのでまあ予想通りですが・・・。(なぜ今まで思いつかなかったのか)

実装

golangのagoutiというWebDriverクライアントを利用して実装してます。(実際にはChromeDriverを使いました)
開発はMacで行ってます。

サンプルソースを↓こちらに置いておきます。
※このソースをそのまま貼り付けても動きません。URLやパラメーターは調整する必要があります。

github.com

  • ChromeDriverを起動するためのoption
options := agouti.ChromeOptions(
        "args", []string{
                "--headless",
                "-disable-gpu", // 暫定的に必要とのこと
                "--no-sandbox",
                "--disable-xss-auditor",
        })

optionをつけなければChromeブラウザが普通に上がります。
デバッグをするときはその方が便利です。

  • Web認証ページの指定
page.Navigate("https://xxx.xxx.xxx.xxx:99999/proxy?foo=bar&hogehoge=http://neverssl.com")

page.Navigate() の引数に認証ページを指定しています。
私の環境ではリダイレクト先のhttpsじゃないサイトをパラメーターで指定することになってます。(最近はhttpsが多いのでrebuild.fmで言ってたneverssl.comを指定してます)

  • ユーザID
page.FindByID("user").Fill("xxxxxxxx")
  • パスワード
page.FirstByName("passwd").Fill("xxxxxxxxxxxxxxx")

パスワードは暗号化したものを外部から渡されて、復号してセットするほうがいいと思いますけど、とりあえず・・・
パスワード変えたり、ユーザID変えたりすることも当然ありますからね。

  • ウェイト
time.Sleep(time.Second * 5)

最後にリダイレクトするのをちょっと待ちます。なくても動いたけど念の為に入れてます。

build

Macで作業してるのでクロスコンパイルでLinuxバイナリを作成します。

$ mkdir linux-amd64
$ GOOS=linux GOARCH=amd64 go build -o linux-amd64/proxyauth ./proxyauth.go

run

  • ChromeDriverを入れておく必要があります

Mac

$ brew cask install chromedriver

Linux

$ sudo apt install chromium-chromedriver

依存するパッケージがやたら多いですがしかたありません。入れてしまいましょう!

認証サイトに直接アクセスするようにしておきます。
何故か大文字のNO_PROXYは効きませんでした。
この辺はツールによっていろいろなので、両方指定しておけばいいのかも。

$ export http_proxy=proxy.example.com:9999
$ export HTTP_PROXY=$http_proxy
$ export no_proxy=xxx.xxx.xxx.xxx
$ export NO_PROXY=no_proxy

今の所、失敗せずに一発で認証が通るようになってます!