Passport.jsのDigest認証で詰んだ話(express 4)

express4でdigest認証を使う為にpassport.jsを使って実装しようとしたらバグに直面した話です。

リクエストURL (req.url)とpassportの資格情報で提供されたURI(cred.uri)が異なっている場合、

400エラーを返すみたいなのですが、Express4ではリクエストURLと資格情報URIがどうやっても異なる為、正しいリクエストを行っても不一致となるようです。

本来期待するURL(cred.uriに相当): /api/v1/aaa/bbb/ccc

req.urlの値: /v1/aaa/bbb/ccc

if (req.url !== creds.uri) { //該当の箇所
    return this.fail(400);
}

対策記事を見つけたのでやってみた(失敗)

以下の記事では、passportによる処理を行う前にルーティングを追加して、事前にreq.urlの値を書き換える手法で回避策を行ったようですが、当方の環境では上手く回避できませんでした。

(req.urlの値を直接書き換えてしまうと、不具合が発生する? ようで、後の処理で 404を返すようになってしまいました)

Digest authentication with Express 4

//追加した処理
router.all('/*', function(req, res, next{
    req.url = (req.baseUrl ? req.baseUrl : "") + req.url;
    next();
}

//もともとやりたい処理
router.all('/v1/aaa/bbb/ccc', your_passport_function());

なので、上記方法は断念。

対策記事を見つけたのでやってみた2

passport-httpモジュールのgithubページにはすでにpull requestも上がっているようで、

以下のように該当コードを修正するリクエストが投げられていました。

Now it works with Express 4+ relative urls #49

が、かなり長い間取り込まれていないようですね。

あまりソースを書き換える事はしたくなかったのですが、以下のように書き換えたところ、正常に動作しました。

試した事1では直接req.urlを書き換えていましたが、こちらでは、if文の中で期待する値を生成しているようですね。なるほど。

112行目〜118行目あたり

if (!creds.username) {
     return this.fail(this._challenge());
   }
// if (req.url !== creds.uri) {  削除
   if (((req.baseUrl?req.baseUrl:"")+req.url) !== creds.uri) { //追加
     return this.fail(400);
   }

express自体も勉強しながら直面したバグだったので、

試した事1で上手く動作させる方法があったらコメントいただけると助かります。

/以上