Commit d870c64a authored by James Edwards-Jones's avatar James Edwards-Jones Committed by James Lopez

OmniAuth full_host spec helper

Allows us to correctly set omniauth's full_host
so redirects take the port into account.

Needed when running selenium tests on a different port
parent f3403f21
import initU2F from '~/shared/sessions/u2f';
document.addEventListener('DOMContentLoaded', initU2F);
---
title: Ensure U2F javascript runs on GroupSAML callback
merge_request: 14262
author:
type: fixed
...@@ -90,7 +90,8 @@ constraints(::Constraints::GroupUrlConstrainer.new) do ...@@ -90,7 +90,8 @@ constraints(::Constraints::GroupUrlConstrainer.new) do
end end
resource :saml_providers, path: 'saml', only: [:show, :create, :update] do resource :saml_providers, path: 'saml', only: [:show, :create, :update] do
post :callback, to: 'omniauth_callbacks#group_saml' callback_methods = Rails.env.test? ? [:get, :post] : [:post]
match :callback, to: 'omniauth_callbacks#group_saml', via: callback_methods
get :sso, to: 'sso#saml' get :sso, to: 'sso#saml'
delete :unlink, to: 'sso#unlink' delete :unlink, to: 'sso#unlink'
end end
......
...@@ -22,6 +22,10 @@ module OmniAuth ...@@ -22,6 +22,10 @@ module OmniAuth
settings = Gitlab::Auth::GroupSaml::DynamicSettings.new(group_lookup.group).to_h settings = Gitlab::Auth::GroupSaml::DynamicSettings.new(group_lookup.group).to_h
env['omniauth.strategy'].options.merge!(settings) env['omniauth.strategy'].options.merge!(settings)
if OmniAuth.config.test_mode && on_request_path?
emulate_relay_state
end
super super
end end
...@@ -50,6 +54,10 @@ module OmniAuth ...@@ -50,6 +54,10 @@ module OmniAuth
end end
end end
def emulate_relay_state
request.query_string.sub!('redirect_to', 'RelayState')
end
def self.invalid_group!(path) def self.invalid_group!(path)
raise ActionController::RoutingError, path raise ActionController::RoutingError, path
end end
...@@ -58,6 +66,19 @@ module OmniAuth ...@@ -58,6 +66,19 @@ module OmniAuth
env['PATH_INFO'] =~ Gitlab::PathRegex.saml_callback_regex env['PATH_INFO'] =~ Gitlab::PathRegex.saml_callback_regex
end end
override :callback_path
def callback_path
@callback_path ||= begin
if options[:callback_path].call(env)
current_path
elsif group_lookup.path
"/groups/#{group_lookup.path}/-/saml/callback"
else
super
end
end
end
private private
def metadata_phase? def metadata_phase?
......
...@@ -13,6 +13,10 @@ describe 'SAML provider settings' do ...@@ -13,6 +13,10 @@ describe 'SAML provider settings' do
group.add_owner(user) group.add_owner(user)
end end
around(:all) do |example|
with_omniauth_full_host { example.run }
end
def submit def submit
click_button('Save changes') click_button('Save changes')
end end
...@@ -138,8 +142,7 @@ describe 'SAML provider settings' do ...@@ -138,8 +142,7 @@ describe 'SAML provider settings' do
let!(:saml_provider) { create(:saml_provider, group: group) } let!(:saml_provider) { create(:saml_provider, group: group) }
before do before do
sign_in(user) mock_group_saml(uid: '123')
allow_any_instance_of(OmniAuth::Strategies::GroupSaml).to receive(:callback_url) { callback_path }
end end
it 'POSTs to the SSO path for the group' do it 'POSTs to the SSO path for the group' do
...@@ -147,7 +150,8 @@ describe 'SAML provider settings' do ...@@ -147,7 +150,8 @@ describe 'SAML provider settings' do
test_sso test_sso
expect(current_path).to eq callback_path expect(current_path).to eq group_saml_providers_path(group)
expect(page).to have_content("SAML for #{group.name} was added to your connected accounts")
end end
end end
end end
...@@ -177,10 +181,6 @@ describe 'SAML provider settings' do ...@@ -177,10 +181,6 @@ describe 'SAML provider settings' do
context 'with existing SAML provider' do context 'with existing SAML provider' do
let!(:saml_provider) { create(:saml_provider, group: group) } let!(:saml_provider) { create(:saml_provider, group: group) }
before do
allow_any_instance_of(OmniAuth::Strategies::GroupSaml).to receive(:callback_url) { callback_path }
end
context 'when not signed in' do context 'when not signed in' do
it "shows the sso page so user can sign in" do it "shows the sso page so user can sign in" do
visit sso_group_saml_providers_path(group) visit sso_group_saml_providers_path(group)
...@@ -205,16 +205,20 @@ describe 'SAML provider settings' do ...@@ -205,16 +205,20 @@ describe 'SAML provider settings' do
end end
it 'Authorize/link button redirects to auth flow' do it 'Authorize/link button redirects to auth flow' do
external_uid = '98765'
mock_group_saml(uid: external_uid)
visit sso_group_saml_providers_path(group) visit sso_group_saml_providers_path(group)
click_link 'Authorize' click_link 'Authorize'
expect(current_path).to eq callback_path expect(page).to have_content(/SAML for .* was added to your connected accounts/)
expect(user.identities.last.extern_uid).to eq external_uid
end end
context 'with linked account' do context 'with linked account' do
before do before do
create(:group_saml_identity, saml_provider: saml_provider, user: user) identity = create(:group_saml_identity, saml_provider: saml_provider, user: user)
mock_group_saml(uid: identity.extern_uid)
end end
it 'Sign in button redirects to auth flow' do it 'Sign in button redirects to auth flow' do
...@@ -222,7 +226,8 @@ describe 'SAML provider settings' do ...@@ -222,7 +226,8 @@ describe 'SAML provider settings' do
click_link 'Sign in with Single Sign-On' click_link 'Sign in with Single Sign-On'
expect(current_path).to eq callback_path expect(current_path).to eq group_path(group)
expect(page).to have_content('Already signed in')
end end
end end
end end
......
...@@ -3,6 +3,7 @@ require 'spec_helper' ...@@ -3,6 +3,7 @@ require 'spec_helper'
describe 'Login' do describe 'Login' do
include LdapHelpers include LdapHelpers
include UserLoginHelper include UserLoginHelper
include DeviseHelpers
before do before do
stub_licensed_features(extended_audit_events: true) stub_licensed_features(extended_audit_events: true)
...@@ -148,4 +149,39 @@ describe 'Login' do ...@@ -148,4 +149,39 @@ describe 'Login' do
end end
end end
end end
describe 'via Group SAML' do
let(:saml_provider) { create(:saml_provider) }
let(:group) { saml_provider.group }
let(:identity) { create(:group_saml_identity, user: user, saml_provider: saml_provider) }
before do
stub_licensed_features(group_saml: true)
end
around(:all) do |example|
with_omniauth_full_host { example.run }
end
context 'with U2F two factor', :js do
let(:user) { create(:user, :two_factor_via_u2f) }
before do
mock_group_saml(uid: identity.extern_uid)
end
it 'shows U2F prompt after SAML' do
visit sso_group_saml_providers_path(group, token: group.saml_discovery_token)
click_link 'Sign in with Single Sign-On'
expect(page).to have_content('Trying to communicate with your device')
expect(page).to have_link('Sign in via 2FA code')
fake_successful_u2f_authentication
expect(current_path).to eq root_path
end
end
end
end end
# frozen_string_literal: true
module EE
module LoginHelpers
def configure_group_saml_mock_auth(uid:)
name = 'My name'
email = 'name@example.com'
response_object = { document: saml_xml(File.read('spec/fixtures/authentication/saml_response.xml')) }
OmniAuth.config.mock_auth[:group_saml] = OmniAuth::AuthHash.new({
provider: :group_saml,
uid: uid,
info: { name: name, email: email },
extra: {
raw_info: { info: { name: name, email: email } },
response_object: response_object
}
})
end
def mock_group_saml(uid:)
allow(Devise).to receive(:omniauth_providers).and_return(%i(group_saml))
allow_any_instance_of(::Gitlab::Auth::SamlOriginValidator).to receive(:gitlab_initiated?).and_return(true)
configure_group_saml_mock_auth(uid: uid)
stub_omniauth_provider(:group_saml)
end
end
end
...@@ -16,16 +16,8 @@ describe 'OAuth Login', :js, :allow_forgery_protection do ...@@ -16,16 +16,8 @@ describe 'OAuth Login', :js, :allow_forgery_protection do
providers = [:github, :twitter, :bitbucket, :gitlab, :google_oauth2, providers = [:github, :twitter, :bitbucket, :gitlab, :google_oauth2,
:facebook, :cas3, :auth0, :authentiq, :salesforce] :facebook, :cas3, :auth0, :authentiq, :salesforce]
before(:all) do around(:all) do |example|
# The OmniAuth `full_host` parameter doesn't get set correctly (it gets set to something like `http://localhost` with_omniauth_full_host { example.run }
# here), and causes integration tests to fail with 404s. We set the `full_host` by removing the request path (and
# anything after it) from the request URI.
@omniauth_config_full_host = OmniAuth.config.full_host
OmniAuth.config.full_host = ->(request) { request['REQUEST_URI'].sub(/#{request['REQUEST_PATH']}.*/, '') }
end
after(:all) do
OmniAuth.config.full_host = @omniauth_config_full_host
end end
def login_with_provider(provider, enter_two_factor: false) def login_with_provider(provider, enter_two_factor: false)
......
...@@ -21,4 +21,16 @@ module DeviseHelpers ...@@ -21,4 +21,16 @@ module DeviseHelpers
context.env context.env
end end
end end
def with_omniauth_full_host(&block)
# The OmniAuth `full_host` parameter doesn't get set correctly (it gets set to something like `http://localhost`
# here), and causes integration tests to fail with 404s. We set the `full_host` by removing the request path (and
# anything after it) from the request URI.
omniauth_config_full_host = OmniAuth.config.full_host
OmniAuth.config.full_host = ->(request) { ActionDispatch::Request.new(request).base_url }
yield
OmniAuth.config.full_host = omniauth_config_full_host
end
end end
...@@ -32,6 +32,10 @@ class FakeU2fDevice ...@@ -32,6 +32,10 @@ class FakeU2fDevice
") ")
end end
def fake_u2f_authentication
@page.execute_script("window.gl.u2fAuthenticate.renderAuthenticated('abc');")
end
private private
def u2f_device(app_id) def u2f_device(app_id)
......
...@@ -87,12 +87,17 @@ module LoginHelpers ...@@ -87,12 +87,17 @@ module LoginHelpers
click_link "oauth-login-#{provider}" click_link "oauth-login-#{provider}"
end end
def fake_successful_u2f_authentication
allow(U2fRegistration).to receive(:authenticate).and_return(true)
FakeU2fDevice.new(page, nil).fake_u2f_authentication
end
def mock_auth_hash_with_saml_xml(provider, uid, email, saml_response) def mock_auth_hash_with_saml_xml(provider, uid, email, saml_response)
response_object = { document: saml_xml(saml_response) } response_object = { document: saml_xml(saml_response) }
mock_auth_hash(provider, uid, email, response_object: response_object) mock_auth_hash(provider, uid, email, response_object: response_object)
end end
def mock_auth_hash(provider, uid, email, response_object: nil) def configure_mock_auth(provider, uid, email, response_object: nil)
# The mock_auth configuration allows you to set per-provider (or default) # The mock_auth configuration allows you to set per-provider (or default)
# authentication hashes to return during integration testing. # authentication hashes to return during integration testing.
OmniAuth.config.mock_auth[provider.to_sym] = OmniAuth::AuthHash.new({ OmniAuth.config.mock_auth[provider.to_sym] = OmniAuth::AuthHash.new({
...@@ -118,6 +123,11 @@ module LoginHelpers ...@@ -118,6 +123,11 @@ module LoginHelpers
response_object: response_object response_object: response_object
} }
}) })
end
def mock_auth_hash(provider, uid, email, response_object: nil)
configure_mock_auth(provider, uid, email, response_object: response_object)
original_env_config_omniauth_auth = Rails.application.env_config['omniauth.auth'] original_env_config_omniauth_auth = Rails.application.env_config['omniauth.auth']
Rails.application.env_config['omniauth.auth'] = OmniAuth.config.mock_auth[provider.to_sym] Rails.application.env_config['omniauth.auth'] = OmniAuth.config.mock_auth[provider.to_sym]
...@@ -199,3 +209,5 @@ module LoginHelpers ...@@ -199,3 +209,5 @@ module LoginHelpers
allow(Gitlab::Auth::Saml::Config).to receive_messages({ options: { name: 'saml', groups_attribute: 'groups', external_groups: groups, args: {} } }) allow(Gitlab::Auth::Saml::Config).to receive_messages({ options: { name: 'saml', groups_attribute: 'groups', external_groups: groups, args: {} } })
end end
end end
LoginHelpers.prepend(EE::LoginHelpers)
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment