Skip to content

Commit

Permalink
Merge pull request #144 from toupeira/verify-state-before-using-provi…
Browse files Browse the repository at this point in the history
…der-errors

Verify state before using errors received from provider
  • Loading branch information
BobbyMcWho committed Nov 2, 2021
2 parents 8438b89 + 98553d7 commit 561ddce
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 7 deletions.
6 changes: 3 additions & 3 deletions lib/omniauth/strategies/oauth2.rb
Expand Up @@ -83,10 +83,10 @@ def token_params

def callback_phase # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
error = request.params["error_reason"] || request.params["error"]
if error
fail!(error, CallbackError.new(request.params["error"], request.params["error_description"] || request.params["error_reason"], request.params["error_uri"]))
elsif !options.provider_ignores_state && (request.params["state"].to_s.empty? || request.params["state"] != session.delete("omniauth.state"))
if !options.provider_ignores_state && (request.params["state"].to_s.empty? || request.params["state"] != session.delete("omniauth.state"))
fail!(:csrf_detected, CallbackError.new(:csrf_detected, "CSRF detected"))
elsif error
fail!(error, CallbackError.new(request.params["error"], request.params["error_description"] || request.params["error_reason"], request.params["error_uri"]))
else
self.access_token = build_access_token
self.access_token = access_token.refresh! if access_token.expired?
Expand Down
41 changes: 37 additions & 4 deletions spec/omniauth/strategies/oauth2_spec.rb
Expand Up @@ -97,14 +97,47 @@ def app
end

describe "#callback_phase" do
subject { fresh_strategy }
it "calls fail with the client error received" do
instance = subject.new("abc", "def")
subject(:instance) { fresh_strategy.new("abc", "def") }

let(:params) { {"error_reason" => "user_denied", "error" => "access_denied", "state" => state} }
let(:state) { "secret" }

before do
allow(instance).to receive(:request) do
double("Request", :params => {"error_reason" => "user_denied", "error" => "access_denied"})
double("Request", :params => params)
end

allow(instance).to receive(:session) do
double("Session", :delete => state)
end
end

it "calls fail with the error received" do
expect(instance).to receive(:fail!).with("user_denied", anything)

instance.callback_phase
end

it "calls fail with the error received if state is missing and CSRF verification is disabled" do
params["state"] = nil
instance.options.provider_ignores_state = true

expect(instance).to receive(:fail!).with("user_denied", anything)

instance.callback_phase
end

it "calls fail with a CSRF error if the state is missing" do
params["state"] = nil

expect(instance).to receive(:fail!).with(:csrf_detected, anything)
instance.callback_phase
end

it "calls fail with a CSRF error if the state is invalid" do
params["state"] = "invalid"

expect(instance).to receive(:fail!).with(:csrf_detected, anything)
instance.callback_phase
end
end
Expand Down

0 comments on commit 561ddce

Please sign in to comment.