Coverage for Auth::OmniauthCallbacks controller (#26147)
				
					
				
			This commit is contained in:
		
							
								
								
									
										4
									
								
								.github/workflows/test-ruby.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										4
									
								
								.github/workflows/test-ruby.yml
									
									
									
									
										vendored
									
									
								
							@@ -107,6 +107,10 @@ jobs:
 | 
			
		||||
      PAM_ENABLED: true
 | 
			
		||||
      PAM_DEFAULT_SERVICE: pam_test
 | 
			
		||||
      PAM_CONTROLLED_SERVICE: pam_test_controlled
 | 
			
		||||
      OIDC_ENABLED: true
 | 
			
		||||
      OIDC_SCOPE: read
 | 
			
		||||
      SAML_ENABLED: true
 | 
			
		||||
      CAS_ENABLED: true
 | 
			
		||||
      BUNDLE_WITH: 'pam_authentication test'
 | 
			
		||||
      CI_JOBS: ${{ matrix.ci_job }}/4
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -5,21 +5,13 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
 | 
			
		||||
 | 
			
		||||
  def self.provides_callback_for(provider)
 | 
			
		||||
    define_method provider do
 | 
			
		||||
      @provider = provider
 | 
			
		||||
      @user = User.find_for_oauth(request.env['omniauth.auth'], current_user)
 | 
			
		||||
 | 
			
		||||
      if @user.persisted?
 | 
			
		||||
        LoginActivity.create(
 | 
			
		||||
          user: @user,
 | 
			
		||||
          success: true,
 | 
			
		||||
          authentication_method: :omniauth,
 | 
			
		||||
          provider: provider,
 | 
			
		||||
          ip: request.remote_ip,
 | 
			
		||||
          user_agent: request.user_agent
 | 
			
		||||
        )
 | 
			
		||||
 | 
			
		||||
        record_login_activity
 | 
			
		||||
        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) if is_navigational_format?
 | 
			
		||||
        set_flash_message(:notice, :success, kind: label_for_provider) if is_navigational_format?
 | 
			
		||||
      else
 | 
			
		||||
        session["devise.#{provider}_data"] = request.env['omniauth.auth']
 | 
			
		||||
        redirect_to new_user_registration_url
 | 
			
		||||
@@ -38,4 +30,29 @@ class Auth::OmniauthCallbacksController < Devise::OmniauthCallbacksController
 | 
			
		||||
      auth_setup_path(missing_email: '1')
 | 
			
		||||
    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
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										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
 | 
			
		||||
		Reference in New Issue
	
	Block a user