🦧

docker環境でrspecで403エラーが出た時の解決

2021/08/28に公開

はじめに

※ 記事というよりあとから「こう考えたらよかった」っていう自分用のメモです。

何が起こったか

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

解決はできたものの駄目だった思考

  1. 403ってどういうコードやっけ?ユーザーのアクセス権限がない?ログインとかの話か?
  2. home_pathでは認証がないので403が出るのは謎、どういうこと?
  3. 「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 &lt;&lt; \"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.comDNSリバインディングやその他の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にしてあげることが本質的な解決ですね。

まとめ

エラーは成長する最高のチャンスということで、「次から同じエラーを出さないためにどういう知識を得たら良いか」という考え方で挑むのが最高ってわけ。

参考

Configuring Middleware

Discussion