docker環境でrspecで403エラーが出た時の解決
はじめに
※ 記事というよりあとから「こう考えたらよかった」っていう自分用のメモです。
何が起こったか
docker環境でrspecでrequest testを実行したところ以下のエラーが発生
get home_path
expect(response).to have_http_status(200)
# エラー
Failure/Error: expect(response).to have_http_status(200)
expected the response to have status code 200 but it was 403
解決はできたものの駄目だった思考
- 403ってどういうコードやっけ?ユーザーのアクセス権限がない?ログインとかの話か?
- home_pathでは認証がないので403が出るのは謎、どういうこと?
- 「rails rspec 403」と調べたら この記事がヒットしたのでなんとなくで解決できた。
う〜ん、こりゃ駄目や。
修正
エラーコードの理解が間違ってた
クライアント側が正しい認証情報を持っていない場合のエラーコードは403ではなく401 unorthorizedであり、それ以外の理由でリソースが操作できない場合403を返します。なので認識が間違っておりました。
エラーコードのレスポンスボディを見て解決
エラーが出た場合、レスポンスに詳細が書いてあるので見た方がよかったですね。ってなわけでbyebugを挟んで確認すると
.
.
<h2>To allow requests to www.example.com, add the following to your environment configuration:</h2>\n <pre>config.hosts << \"www.example.com\"</pre>\n</div>\n\n\n</body>\n</html>\n"
.
まさにありましたね。
# test.rb
Rails.application.configure do
.
.
.
config.hosts << "www.example.com
はい勝利、と思いきや同じエラーが出ました。それならばひょっとすると環境がtestはない、という可能性が考えられますね。
そこで環境を出力するとやはりdevelopment
となっていました。
# rails_helper.rb
.
.
ENV['RAILS_ENV'] ||= 'test'
rails_helper.rbを確認すると環境変数を設定してしまっている状態だとtest環境とならないようですね。
これはdockerで環境を構築する際、環境変数としてRAILS_ENV= developmentと設定していたのが原因でした。
そこで試しに
# rails_helper.rb
ENV['RAILS_ENV'] ||= 'test'
を
ENV['RAILS_ENV'] = 'test'
に修正
とすると、403エラー自体がなくなりました。
DNSリバインディング対策の設定
config.hosts << "www.example.com
は DNSリバインディングやその他のHost header attackへの対策に使われます。
development環境では以下のように設定されていますが、productとtestにはデフォルトの設定がなくhostのチェックは行われません。
Rails.application.config.hosts = [
IPAddr.new("0.0.0.0/0"), # All IPv4 addresses.
IPAddr.new("::/0"), # All IPv6 addresses.
"localhost" # The localhost reserved domain.
]
ということは、ダメな解決法では
development環境になっていたためhostのチェックが行われconfig.hosts << "www.example.com
にすれば表面上エラーがなくなった、といった感じでした。
なので環境をtestにしてあげることが本質的な解決ですね。
まとめ
エラーは成長する最高のチャンスということで、「次から同じエラーを出さないためにどういう知識を得たら良いか」という考え方で挑むのが最高ってわけ。
Discussion