mirror of
https://github.com/mastodon/mastodon.git
synced 2024-08-20 21:08:15 -07:00
Coverage for Auth::OmniauthCallbacks
controller (#26147)
This commit is contained in:
parent
f826a95f6e
commit
50ff3d3342
4 changed files with 163 additions and 11 deletions
4
.github/workflows/test-ruby.yml
vendored
4
.github/workflows/test-ruby.yml
vendored
|
@ -107,6 +107,10 @@ jobs:
|
||||||
PAM_ENABLED: true
|
PAM_ENABLED: true
|
||||||
PAM_DEFAULT_SERVICE: pam_test
|
PAM_DEFAULT_SERVICE: pam_test
|
||||||
PAM_CONTROLLED_SERVICE: pam_test_controlled
|
PAM_CONTROLLED_SERVICE: pam_test_controlled
|
||||||
|
OIDC_ENABLED: true
|
||||||
|
OIDC_SCOPE: read
|
||||||
|
SAML_ENABLED: true
|
||||||
|
CAS_ENABLED: true
|
||||||
BUNDLE_WITH: 'pam_authentication test'
|
BUNDLE_WITH: 'pam_authentication test'
|
||||||
CI_JOBS: ${{ matrix.ci_job }}/4
|
CI_JOBS: ${{ matrix.ci_job }}/4
|
||||||
|
|
||||||
|
|
|
@ -5,21 +5,13 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||||
|
|
||||||
def self.provides_callback_for(provider)
|
def self.provides_callback_for(provider)
|
||||||
define_method provider do
|
define_method provider do
|
||||||
|
@provider = provider
|
||||||
@user = User.find_for_oauth(request.env['omniauth.auth'], current_user)
|
@user = User.find_for_oauth(request.env['omniauth.auth'], current_user)
|
||||||
|
|
||||||
if @user.persisted?
|
if @user.persisted?
|
||||||
LoginActivity.create(
|
record_login_activity
|
||||||
user: @user,
|
|
||||||
success: true,
|
|
||||||
authentication_method: :omniauth,
|
|
||||||
provider: provider,
|
|
||||||
ip: request.remote_ip,
|
|
||||||
user_agent: request.user_agent
|
|
||||||
)
|
|
||||||
|
|
||||||
sign_in_and_redirect @user, event: :authentication
|
sign_in_and_redirect @user, event: :authentication
|
||||||
label = Devise.omniauth_configs[provider]&.strategy&.display_name.presence || I18n.t("auth.providers.#{provider}", default: provider.to_s.chomp('_oauth2').capitalize)
|
set_flash_message(:notice, :success, kind: label_for_provider) if is_navigational_format?
|
||||||
set_flash_message(:notice, :success, kind: label) if is_navigational_format?
|
|
||||||
else
|
else
|
||||||
session["devise.#{provider}_data"] = request.env['omniauth.auth']
|
session["devise.#{provider}_data"] = request.env['omniauth.auth']
|
||||||
redirect_to new_user_registration_url
|
redirect_to new_user_registration_url
|
||||||
|
@ -38,4 +30,29 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
|
||||||
auth_setup_path(missing_email: '1')
|
auth_setup_path(missing_email: '1')
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
private
|
||||||
|
|
||||||
|
def record_login_activity
|
||||||
|
LoginActivity.create(
|
||||||
|
user: @user,
|
||||||
|
success: true,
|
||||||
|
authentication_method: :omniauth,
|
||||||
|
provider: @provider,
|
||||||
|
ip: request.remote_ip,
|
||||||
|
user_agent: request.user_agent
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
def label_for_provider
|
||||||
|
provider_display_name || configured_provider_name
|
||||||
|
end
|
||||||
|
|
||||||
|
def provider_display_name
|
||||||
|
Devise.omniauth_configs[@provider]&.strategy&.display_name.presence
|
||||||
|
end
|
||||||
|
|
||||||
|
def configured_provider_name
|
||||||
|
I18n.t("auth.providers.#{@provider}", default: @provider.to_s.chomp('_oauth2').capitalize)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
124
spec/requests/omniauth_callbacks_spec.rb
Normal file
124
spec/requests/omniauth_callbacks_spec.rb
Normal file
|
@ -0,0 +1,124 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
require 'rails_helper'
|
||||||
|
|
||||||
|
describe 'OmniAuth callbacks' do
|
||||||
|
shared_examples 'omniauth provider callbacks' do |provider|
|
||||||
|
subject { post send "user_#{provider}_omniauth_callback_path" }
|
||||||
|
|
||||||
|
context 'with full information in response' do
|
||||||
|
before do
|
||||||
|
mock_omniauth(provider, {
|
||||||
|
provider: provider.to_s,
|
||||||
|
uid: '123',
|
||||||
|
info: {
|
||||||
|
verified: 'true',
|
||||||
|
email: 'user@host.example',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'without a matching user' do
|
||||||
|
it 'creates a user and an identity and redirects to root path' do
|
||||||
|
expect { subject }
|
||||||
|
.to change(User, :count)
|
||||||
|
.by(1)
|
||||||
|
.and change(Identity, :count)
|
||||||
|
.by(1)
|
||||||
|
.and change(LoginActivity, :count)
|
||||||
|
.by(1)
|
||||||
|
|
||||||
|
expect(User.last.email).to eq('user@host.example')
|
||||||
|
expect(Identity.find_by(user: User.last).uid).to eq('123')
|
||||||
|
expect(response).to redirect_to(root_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a matching user and no matching identity' do
|
||||||
|
before do
|
||||||
|
Fabricate(:user, email: 'user@host.example')
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'matches the existing user, creates an identity, and redirects to root path' do
|
||||||
|
expect { subject }
|
||||||
|
.to not_change(User, :count)
|
||||||
|
.and change(Identity, :count)
|
||||||
|
.by(1)
|
||||||
|
.and change(LoginActivity, :count)
|
||||||
|
.by(1)
|
||||||
|
|
||||||
|
expect(Identity.find_by(user: User.last).uid).to eq('123')
|
||||||
|
expect(response).to redirect_to(root_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a matching user and a matching identity' do
|
||||||
|
before do
|
||||||
|
user = Fabricate(:user, email: 'user@host.example')
|
||||||
|
Fabricate(:identity, user: user, uid: '123', provider: provider)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'matches the existing records and redirects to root path' do
|
||||||
|
expect { subject }
|
||||||
|
.to not_change(User, :count)
|
||||||
|
.and not_change(Identity, :count)
|
||||||
|
.and change(LoginActivity, :count)
|
||||||
|
.by(1)
|
||||||
|
|
||||||
|
expect(response).to redirect_to(root_path)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'with a response missing email address' do
|
||||||
|
before do
|
||||||
|
mock_omniauth(provider, {
|
||||||
|
provider: provider.to_s,
|
||||||
|
uid: '123',
|
||||||
|
info: {
|
||||||
|
verified: 'true',
|
||||||
|
},
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'redirects to the auth setup page' do
|
||||||
|
expect { subject }
|
||||||
|
.to change(User, :count)
|
||||||
|
.by(1)
|
||||||
|
.and change(Identity, :count)
|
||||||
|
.by(1)
|
||||||
|
.and change(LoginActivity, :count)
|
||||||
|
.by(1)
|
||||||
|
|
||||||
|
expect(response).to redirect_to(auth_setup_path(missing_email: '1'))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
context 'when a user cannot be built' do
|
||||||
|
before do
|
||||||
|
allow(User).to receive(:find_for_oauth).and_return(User.new)
|
||||||
|
end
|
||||||
|
|
||||||
|
it 'redirects to the new user signup page' do
|
||||||
|
expect { subject }
|
||||||
|
.to not_change(User, :count)
|
||||||
|
.and not_change(Identity, :count)
|
||||||
|
.and not_change(LoginActivity, :count)
|
||||||
|
|
||||||
|
expect(response).to redirect_to(new_user_registration_url)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#openid_connect', if: ENV['OIDC_ENABLED'] == 'true' && ENV['OIDC_SCOPE'].present? do
|
||||||
|
include_examples 'omniauth provider callbacks', :openid_connect
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#cas', if: ENV['CAS_ENABLED'] == 'true' do
|
||||||
|
include_examples 'omniauth provider callbacks', :cas
|
||||||
|
end
|
||||||
|
|
||||||
|
describe '#saml', if: ENV['SAML_ENABLED'] == 'true' do
|
||||||
|
include_examples 'omniauth provider callbacks', :saml
|
||||||
|
end
|
||||||
|
end
|
7
spec/support/omniauth_mocks.rb
Normal file
7
spec/support/omniauth_mocks.rb
Normal file
|
@ -0,0 +1,7 @@
|
||||||
|
# frozen_string_literal: true
|
||||||
|
|
||||||
|
OmniAuth.config.test_mode = true
|
||||||
|
|
||||||
|
def mock_omniauth(provider, data)
|
||||||
|
OmniAuth.config.mock_auth[provider] = OmniAuth::AuthHash.new(data)
|
||||||
|
end
|
Loading…
Reference in a new issue