-
Notifications
You must be signed in to change notification settings - Fork 53
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* DEV: Update ruby linting * Use named subjects in specs --------- Co-authored-by: Loïc Guitaut <[email protected]>
- Loading branch information
Showing
2 changed files
with
98 additions
and
83 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,15 @@ | |
require "rails_helper" | ||
|
||
describe OmniAuth::Strategies::OpenIDConnect do | ||
subject(:strategy) do | ||
OmniAuth::Strategies::OpenIDConnect.new( | ||
app, | ||
"appid", | ||
"secret", | ||
discovery_document: discovery_document, | ||
) | ||
end | ||
|
||
let(:app) do | ||
@app_called = false | ||
lambda do |*args| | ||
|
@@ -21,117 +30,112 @@ | |
} | ||
end | ||
|
||
subject do | ||
OmniAuth::Strategies::OpenIDConnect.new( | ||
app, | ||
"appid", | ||
"secret", | ||
discovery_document: discovery_document, | ||
) | ||
end | ||
|
||
before { OmniAuth.config.test_mode = true } | ||
|
||
after { OmniAuth.config.test_mode = false } | ||
|
||
it "throws error for missing discovery document" do | ||
strategy = | ||
OmniAuth::Strategies::OpenIDConnect.new(app, "appid", "secret", discovery_document: nil) | ||
expect { strategy.discover! }.to raise_error(::OmniAuth::OpenIDConnect::DiscoveryError) | ||
context "when discovery document is missing" do | ||
let(:discovery_document) { nil } | ||
|
||
it "throws an error" do | ||
expect { strategy.discover! }.to raise_error(::OmniAuth::OpenIDConnect::DiscoveryError) | ||
end | ||
end | ||
|
||
it "throws error for invalid discovery document" do | ||
discovery_document.delete("authorization_endpoint") | ||
expect { subject.discover! }.to raise_error(::OmniAuth::OpenIDConnect::DiscoveryError) | ||
expect { strategy.discover! }.to raise_error(::OmniAuth::OpenIDConnect::DiscoveryError) | ||
end | ||
|
||
it "disables userinfo if not included in discovery document" do | ||
discovery_document.delete("userinfo_endpoint") | ||
subject.discover! | ||
expect(subject.options.use_userinfo).to eq(false) | ||
strategy.discover! | ||
expect(strategy.options.use_userinfo).to eq(false) | ||
end | ||
|
||
it "uses basic authentication when no endpoint auth methods are provided" do | ||
subject.discover! | ||
expect(subject.options.client_options.auth_scheme).to eq(:basic_auth) | ||
strategy.discover! | ||
expect(strategy.options.client_options.auth_scheme).to eq(:basic_auth) | ||
end | ||
|
||
it "uses basic authentication when both client_secret_basic and client_secret_post are provided" do | ||
discovery_document.merge!( | ||
{ "token_endpoint_auth_methods_supported" => %w[client_secret_basic client_secret_post] }, | ||
) | ||
subject.discover! | ||
expect(subject.options.client_options.auth_scheme).to eq(:basic_auth) | ||
strategy.discover! | ||
expect(strategy.options.client_options.auth_scheme).to eq(:basic_auth) | ||
end | ||
|
||
it "uses request_body authentication when client_secret_post is provided only" do | ||
discovery_document.merge!({ "token_endpoint_auth_methods_supported" => ["client_secret_post"] }) | ||
subject.discover! | ||
expect(subject.options.client_options.auth_scheme).to eq(:request_body) | ||
strategy.discover! | ||
expect(strategy.options.client_options.auth_scheme).to eq(:request_body) | ||
end | ||
|
||
context "with valid discovery document loaded" do | ||
before do | ||
subject.stubs(:request).returns(mock("object")) | ||
subject | ||
strategy.stubs(:request).returns(mock("object")) | ||
strategy | ||
.request | ||
.stubs(:params) | ||
.returns("p" => "someallowedvalue", "somethingelse" => "notallowed") | ||
subject.options.claims = '{"userinfo":{"email":null,"email_verified":null}' | ||
subject.discover! | ||
strategy.options.claims = '{"userinfo":{"email":null,"email_verified":null}' | ||
strategy.discover! | ||
end | ||
|
||
it "loads parameters correctly" do | ||
expect(subject.options.client_options.site).to eq("https://id.example.com/") | ||
expect(subject.options.client_options.authorize_url).to eq("https://id.example.com/authorize") | ||
expect(subject.options.client_options.token_url).to eq("https://id.example.com/token") | ||
expect(subject.options.client_options.userinfo_endpoint).to eq( | ||
expect(strategy.options.client_options.site).to eq("https://id.example.com/") | ||
expect(strategy.options.client_options.authorize_url).to eq( | ||
"https://id.example.com/authorize", | ||
) | ||
expect(strategy.options.client_options.token_url).to eq("https://id.example.com/token") | ||
expect(strategy.options.client_options.userinfo_endpoint).to eq( | ||
"https://id.example.com/userinfo", | ||
) | ||
end | ||
|
||
describe "authorize parameters" do | ||
it "passes through allowed parameters" do | ||
expect(subject.authorize_params[:p]).to eq("someallowedvalue") | ||
expect(subject.authorize_params[:somethingelse]).to eq(nil) | ||
expect(strategy.authorize_params[:p]).to eq("someallowedvalue") | ||
expect(strategy.authorize_params[:somethingelse]).to eq(nil) | ||
|
||
expect(subject.session["omniauth.param.p"]).to eq("someallowedvalue") | ||
expect(strategy.session["omniauth.param.p"]).to eq("someallowedvalue") | ||
end | ||
|
||
it "sets a nonce" do | ||
expect((nonce = subject.authorize_params[:nonce]).size).to eq(64) | ||
expect(subject.session["omniauth.nonce"]).to eq(nonce) | ||
expect((nonce = strategy.authorize_params[:nonce]).size).to eq(64) | ||
expect(strategy.session["omniauth.nonce"]).to eq(nonce) | ||
end | ||
|
||
it "passes claims through to authorize endpoint if present" do | ||
expect(subject.authorize_params[:claims]).to eq( | ||
expect(strategy.authorize_params[:claims]).to eq( | ||
'{"userinfo":{"email":null,"email_verified":null}', | ||
) | ||
end | ||
|
||
it "does not pass claims if empty string" do | ||
subject.options.claims = "" | ||
expect(subject.authorize_params[:claims]).to eq(nil) | ||
strategy.options.claims = "" | ||
expect(strategy.authorize_params[:claims]).to eq(nil) | ||
end | ||
end | ||
|
||
describe "token parameters" do | ||
it "passes through parameters from authorize phase" do | ||
expect(subject.authorize_params[:p]).to eq("someallowedvalue") | ||
subject.stubs(:request).returns(mock) | ||
subject.request.stubs(:params).returns({}) | ||
expect(subject.token_params[:p]).to eq("someallowedvalue") | ||
expect(strategy.authorize_params[:p]).to eq("someallowedvalue") | ||
strategy.stubs(:request).returns(mock) | ||
strategy.request.stubs(:params).returns({}) | ||
expect(strategy.token_params[:p]).to eq("someallowedvalue") | ||
end | ||
end | ||
|
||
describe "callback_phase" do | ||
before do | ||
auth_params = subject.authorize_params | ||
auth_params = strategy.authorize_params | ||
|
||
subject.stubs(:full_host).returns("https://example.com") | ||
strategy.stubs(:full_host).returns("https://example.com") | ||
|
||
subject.stubs(:request).returns(mock) | ||
subject | ||
strategy.stubs(:request).returns(mock) | ||
strategy | ||
.request | ||
.stubs(:params) | ||
.returns("state" => auth_params[:state], "code" => "supersecretcode") | ||
|
@@ -150,17 +154,17 @@ | |
end | ||
|
||
it "handles error redirects correctly" do | ||
subject.stubs(:request).returns(mock) | ||
subject | ||
strategy.stubs(:request).returns(mock) | ||
strategy | ||
.request | ||
.stubs(:params) | ||
.returns("error" => true, "error_description" => "User forgot password") | ||
subject.options.error_handler = | ||
strategy.options.error_handler = | ||
lambda do |error, message| | ||
return "https://example.com/error_redirect" if message.include?("forgot password") | ||
end | ||
expect(subject.callback_phase[0]).to eq(302) | ||
expect(subject.callback_phase[1]["Location"]).to eq("https://example.com/error_redirect") | ||
expect(strategy.callback_phase[0]).to eq(302) | ||
expect(strategy.callback_phase[1]["Location"]).to eq("https://example.com/error_redirect") | ||
expect(@app_called).to eq(false) | ||
end | ||
|
||
|
@@ -176,27 +180,27 @@ | |
}, | ||
) | ||
|
||
subject.options.use_userinfo = false | ||
strategy.options.use_userinfo = false | ||
end | ||
|
||
it "fetches auth token correctly, and uses it for user info" do | ||
expect(subject.callback_phase[0]).to eq(200) | ||
expect(subject.uid).to eq("someuserid") | ||
expect(subject.info[:name]).to eq("My Auth Token Name") | ||
expect(subject.info[:email]).to eq("[email protected]") | ||
expect(subject.extra[:id_token]).to eq(@token) | ||
expect(strategy.callback_phase[0]).to eq(200) | ||
expect(strategy.uid).to eq("someuserid") | ||
expect(strategy.info[:name]).to eq("My Auth Token Name") | ||
expect(strategy.info[:email]).to eq("[email protected]") | ||
expect(strategy.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) | ||
strategy.session["omniauth.nonce"] = "overriddenNonce" | ||
expect(strategy.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) | ||
strategy.options.client_id = "overriddenclientid" | ||
expect(strategy.callback_phase[0]).to eq(302) | ||
expect(@app_called).to eq(false) | ||
end | ||
end | ||
|
@@ -231,16 +235,16 @@ | |
end | ||
|
||
it "fetches credentials and auth token correctly" do | ||
expect(subject.callback_phase[0]).to eq(200) | ||
expect(subject.uid).to eq("someuserid") | ||
expect(subject.info[:name]).to eq("My Userinfo Name") | ||
expect(subject.info[:email]).to eq("[email protected]") | ||
expect(strategy.callback_phase[0]).to eq(200) | ||
expect(strategy.uid).to eq("someuserid") | ||
expect(strategy.info[:name]).to eq("My Userinfo Name") | ||
expect(strategy.info[:email]).to eq("[email protected]") | ||
expect(@app_called).to eq(true) | ||
end | ||
|
||
it "handles mismatching `sub` correctly" do | ||
userinfo_response["sub"] = "someothersub" | ||
callback_response = subject.callback_phase | ||
callback_response = strategy.callback_phase | ||
expect(callback_response[0]).to eq(302) | ||
expect(callback_response[1]["Location"]).to eq( | ||
"/auth/failure?message=openid_connect_sub_mismatch&strategy=openidconnect", | ||
|