FIX: Ensure nonce mismatch causes auth to fail correctly (#15)
This commit is contained in:
parent
f32c23eece
commit
4aa0e1b4ab
|
@ -9,6 +9,8 @@ module ::OmniAuth
|
|||
|
||||
module Strategies
|
||||
class OpenIDConnect < OmniAuth::Strategies::OAuth2
|
||||
class NonceVerifyError < StandardError; end
|
||||
|
||||
option :scope, "openid"
|
||||
option :discovery, true
|
||||
option :discovery_document, nil
|
||||
|
@ -95,14 +97,13 @@ module ::OmniAuth
|
|||
oauth2_callback_phase = super
|
||||
return oauth2_callback_phase if env['omniauth.error']
|
||||
|
||||
if id_token_info["nonce"].nil? || id_token_info["nonce"].empty? || id_token_info["nonce"] != session.delete("omniauth.nonce")
|
||||
return fail!(:csrf_detected, CallbackError.new(:csrf_detected, "CSRF detected"))
|
||||
end
|
||||
oauth2_callback_phase
|
||||
rescue ::OmniAuth::OpenIDConnect::DiscoveryError => e
|
||||
fail!(:openid_connect_discovery_error, e)
|
||||
rescue ::JWT::DecodeError => e
|
||||
fail!(:jwt_decode_failed, e)
|
||||
rescue NonceVerifyError => e
|
||||
fail!(:jwt_nonce_verify_failed, e)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -124,6 +125,11 @@ module ::OmniAuth
|
|||
verify_iat: false,
|
||||
verify_jti: false
|
||||
)
|
||||
|
||||
if decoded["nonce"].nil? || decoded["nonce"].empty? || decoded["nonce"] != session.delete("omniauth.nonce")
|
||||
raise NonceVerifyError.new "JWT nonce is missing, or does not match"
|
||||
end
|
||||
|
||||
verbose_log("Verified JWT\n\n#{decoded.to_yaml}")
|
||||
|
||||
decoded
|
||||
|
|
|
@ -5,7 +5,9 @@ require 'rails_helper'
|
|||
|
||||
describe OmniAuth::Strategies::OpenIDConnect do
|
||||
let(:app) do
|
||||
@app_called = false
|
||||
lambda do |*args|
|
||||
@app_called = true
|
||||
[200, {}, ['Hello.']]
|
||||
end
|
||||
end
|
||||
|
@ -109,6 +111,7 @@ describe OmniAuth::Strategies::OpenIDConnect do
|
|||
subject.options.error_handler = lambda { |error, message| return "https://example.com/error_redirect" if message.include?("forgot password") }
|
||||
expect(subject.callback_phase[0]).to eq(302)
|
||||
expect(subject.callback_phase[1]["Location"]).to eq("https://example.com/error_redirect")
|
||||
expect(@app_called).to eq(false)
|
||||
end
|
||||
|
||||
context "with userinfo disabled" do
|
||||
|
@ -128,16 +131,19 @@ describe OmniAuth::Strategies::OpenIDConnect do
|
|||
expect(subject.info[:name]).to eq("My Auth Token Name")
|
||||
expect(subject.info[:email]).to eq("tokenemail@example.com")
|
||||
expect(subject.extra[:id_token]).to eq(@token)
|
||||
expect(@app_called).to eq(true)
|
||||
end
|
||||
|
||||
it "checks the nonce" do
|
||||
subject.session["omniauth.nonce"] = "overriddenNonce"
|
||||
expect(subject.callback_phase[0]).to eq(302)
|
||||
expect(@app_called).to eq(false)
|
||||
end
|
||||
|
||||
it "checks the issuer" do
|
||||
subject.options.client_id = "overriddenclientid"
|
||||
expect(subject.callback_phase[0]).to eq(302)
|
||||
expect(@app_called).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -165,6 +171,7 @@ describe OmniAuth::Strategies::OpenIDConnect do
|
|||
expect(subject.uid).to eq("someuserid")
|
||||
expect(subject.info[:name]).to eq("My Userinfo Name")
|
||||
expect(subject.info[:email]).to eq("userinfoemail@example.com")
|
||||
expect(@app_called).to eq(true)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
Loading…
Reference in New Issue