あれ?つながらない!
発端は、iPadでの開発環境を整備しようと思ったからでした。
VPSに開発環境を入れられたら便利だなと思い、Theiaをインストールして、そのままじゃ誰でも使えてしまうので、Apacheをリバースプロキシにして、Digest認証を入れて、さらにSSLにしてと、構築してきました。ところが、PCのブラウザからは期待通りにつながるのですが、iPadだとつながらない。。。
意味ないじゃありませんか!
PCの場合
TheiaはNode.jsでデフォルトでポート3000で動作します。
Apacheをリバースプロキシとして、https://example.com/theia/
を経由してアクセスするよう設定しました。
さらに、TheiaはWebSocketで/theia/services
以下にアクセスするようなので、リバースプロキシ設定で/theia/services/
へのアクセスは、ws://localhost:3000/services/
にアクセスするように設定しています
(詳しくはこちらをご覧ください)。
Apacheのログに主要なリクエストヘッダを出力させた結果が以下になります。
(どのヘッダを出力するかはブラウザの開発者ツールで確認しているのですが、iPadの場合と比較するために、Apacheのログに出力して確認することにしました。)
"GET /theia/services HTTP/1.1" 200
Authorization:"Digest username=\"watashi\", realm=\"DAuth\", nonce=\"xxxxx\", uri=\"/theia/services\", algorithm=MD5, response=\"yyyyy\", qop=auth, nc=0000000c, cnonce=\"zzzzz\"
Sec-WebSocket-Extensions:"permessage-deflate; client_max_window_bits"
Sec-WebSocket-Key:"mfnf6LozGNRKYis+K8NXhQ=="
Sec-WebSocket-Version:"13"
Upgrade:"websocket"
プロトコルが"websocket"にアップグレードされ、Digest認証のためのAuthorizationヘッダもあります(一部編集しています)。
#iPadの場合
"GET /theia/services HTTP/1.1" 401
Authorization:"-"
Sec-WebSocket-Extensions:"x-webkit-deflate-frame"
Sec-WebSocket-Key:"3CEhfYMZMFoXy4yWzU+igQ=="
Sec-WebSocket-Version:"13"
Upgrade:"websocket"
同じサイトにアクセスした結果です。プロトコルが"websocket"にアップグレードされていますが、Digest認証のためのAuthorizationヘッダがありません!
ChromeもSafariも同様でした。
Sec-WebSocket-Extensionsの内容が異なりますが、圧縮に関するパラメータなので関係なさそうです。
それならば...Apache Form認証
『ヘッダがないならCookieを食べればいいのに』との言葉どおり、Cookieを使ったログインセッションで、思惑どおりの動作になるか試してみます。Theiaの改造はおろか、何かそのために作るのは面倒なので、Apache Form認証を利用します。
sudo a2enmod hogehoge
でモジュールを追加する必要がありましたが、私の場合は以下が必要でした。それまでに入れてあるモジュールにもよると思いますので、Apacheを再起動してエラーが出るようであれば、エラーメッセージを参考にして追加してください。
- auth_form
- request
- session_cookie
- session_crypt
- session
サイト構成はこんな感じ。
/ ←ここには何も置かない
|—- auth ←login.htmlとかを置く
|—- theia ←ここをForm認証の対象にする
認証の設定はこんな感じ。httpsのときはhttpのところをhttpsに変えましょう。Basic認証と同じ.htpasswdを作って置きます。
000-default.conf
<Location "/theia">
AuthType Form
AuthName "FormAuth"
AuthUserFile /etc/apache2/.htpasswd
AuthFormProvider file
AuthFormLoginRequiredLocation http://%{SERVER_NAME}/auth/login.html
Session On
SessionCookieName auth_form path=/theia
SessionCryptoPassphrase secure
Require valid-user
</Location>
<Location "/dologin.html">
SetHandler form-login-handler
AuthFormLoginRequiredLocation http://%{SERVER_NAME}/auth/login.html
AuthFormLoginSuccessLocation http://%{SERVER_NAME}/theia/
AuthFormProvider file
AuthUserFile /etc/apache2/.htpasswd
AuthType Form
AuthName "FormAuth"
Session On
SessionCookieName auth_form path=/theia
SessionCryptoPassphrase secure
</Location>
<Location /dologout.html>
SetHandler form-logout-handler
AuthFormLogoutLocation http://%{SERVER_NAME}/auth/loggedout.html
Session On
SessionMaxAge 1
SessionCookieName auth_form path=/theia
SessionCryptoPassphrase secure
</Location>
login.html
<html>
<body>
<h1>Login for Theia.</h1>
<form method="POST" action="/dologin.html">
Username: <input type="text" name="httpd_username" value="" />
<br>
Password: <input type="password" name="httpd_password" value="" />
<input type="submit" name="login" value="Login" />
</form>
</body>
</html>
loggedout.html
<html>
<body>
Logged out.
<br>
<a href="login.html">Login</a>
</body>
</html>
これでようやくできました!
けど、logoutが出番なし