オレオレSSL証明書で運用されているGHEにPassportでログインする
解決方法
つまりstrategy作ってから最後にこうするだけで良い
strategy._oauth2.setAgent(new https.Agent({rejectUnauthorized: false}))
以下詳しく
const strategy = new GithubStrategy({clientID, clientSecret, callbackURL})でstrategy作って
passport.use(strategy, callback)すればログインできる
GitHubだけでなくGHE(GitHub Enterprise)にもログインできる new GithubStrategy(options)のoptionsに
さらにauthorizationURLとtokenURLとuserProfileURLも追加すると、できる
documentには書かれてないが、コード読むとわかる
オプションがどんどん増えてこんな感じになる
code:js
const options = {
authorizationURL: process.env.GHE_HOST + '/login/oauth/authorize',
clientID: process.env.GITHUB_CLIENT_ID,
clientSecret: process.env.GITHUB_CLIENT_SECRET,
callbackURL: process.env.APP_URL + '/auth/github/callback',
state: true
tokenURL: process.env.GHE_HOST + '/login/oauth/access_token',
userAgent: 'scrapbox',
userProfileURL: process.env.GHE_HOST + '/api/v3/user'
}
const strategy = new Strategy(options, onLogin)
そこに普通にpassport-githubでOAuthしようとすると
InternalOAuthError: Failed to obtain access tokenが発生する
間違った解決方法
require('https').globalAgent.options.rejectUnauthorized = false;しろ、と書かれている
もし可能でも、やらないほうが良い
globalAgentを上書きできてしまったら
OAuth以外のライブラリも、全て影響を受けてしまう
危険すぎる
正しい解決方法
oauth npmのhttp agentを差し替える
passportの構造
passport-strategy
passportはフレームワークなので、普通に使うぶんには一番上の層しか意識しなくて済む
しかし、下の方で問題が起こるとコード追うのがけっこう大変
多層構造になっている為
上下のライブラリを行ったり来たりしながら追っていく必要がある
構造としてはpluginで拡張するタイプのフレームワークなら妥当な物だと思う
この辺は複雑性をどう縮減していくかという設計パターンの話で、まあ順当に設計すればpassportみたいになるはずなので、文句はない
このライブラリ内のこのインスタンスは、こっちのライブラリのコレだよな????という突き合わせが必要になってくる
npmの中にconsole.log仕込んで地道に調査していくしかない
やればできる
passport-googleとかだとさらにAPIのバージョン等があって、さらに層が増える
oauth npmが使うhttps agentを差し替える
1つずつライブラリの中のコードを追っていく
同時に使っている他のstrategyに影響を与えちゃったりしないかな?とか
だんだん気になってくるので、コード読まざるを得ない
const strategy = new GithubStrategy(options)で作ったstrategyの
strategy._oauth2が、oauth npmのインスタンスである
これの中のhttp agentを差し替えたい
そういう目的で作られた抜け道がある
oauth npmのOAuth2.prototype.setAgentを呼び出すと、OAuth npmのprototypeの_agentを更新できようになった
2017年1月に実装された
_agentを追っていく
prototype._agentはOAuth2.prototype._executeRequestで使われるhttps agentを上書きできる OAuth2.prototype._executeRequestはOAuth2.prototype._requestから呼び出される
options._agentはハードコーディングされていて、関数_requestの引数からは操作できない
http_library.request(options)で、options.agentとして渡される
http_libraryには、Nodejs標準のhttpとhttpsのどちらかが選ばれる
OAuth endpointのURLをparseして自動的に決定される
つまりhttps.requst(options)になる
https.request(options[, callback])
passport-oauth2が指定しているhttps agentを調べる
agentは標準ライブラリのhttps.requestを呼び出した所で、毎回指定する必要がある
http agent差し替えても、同時に使ってる他のstrategyに影響は無い事がわかった
http agentを差し替える
というわけで
strategy._oauth2.setAgent(new https.Agent({rejectUnauthorized: false}))
という1行を書けば完成なのだが
影響範囲がどこまでなのか、しっかり調べるとコードリーディング大会が開催され、結構大変だった