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_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 | ||||||
		Reference in New Issue
	
	Block a user