Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions config/environments/test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,11 @@

# Fake omniauth for testing
OmniAuth.config.test_mode = true
# Deterministic failure handling: omniauth raises from its FailureEndpoint
# when ENV['RACK_ENV'] is 'development', and Puma's Capybara test server sets
# ENV['RACK_ENV'] ||= 'development' mid-process — so specs running after a
# feature spec would otherwise see raise-out instead of the redirect.
OmniAuth.config.failure_raise_out_environments = []

config.after_initialize do
Bullet.enable = true
Expand Down
9 changes: 6 additions & 3 deletions lib/omniauth/strategies/codebar.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,7 @@ def request_phase
def callback_phase
error = request.params['error']
if error
fail!(:auth_error, StandardError.new(error))
return
return fail!(:auth_error, StandardError.new(error))
end

# Verify state/nonce
Expand Down Expand Up @@ -105,7 +104,11 @@ def callback_phase

call_app!
rescue StandardError => e
return if env['omniauth.error']
raise if @env['omniauth.auth'] # app error after successful auth: not an auth failure

# A failure must return the Rack response from on_failure — a bare return
# gives Rack a nil response and TempfileReaper raises `[]=' for nil`.
return OmniAuth.config.on_failure.call(env) if env['omniauth.error']

fail!(:unknown_error, e)
end
Expand Down
11 changes: 11 additions & 0 deletions spec/lib/omniauth/strategies/codebar_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,17 @@ def build_env(path, query: '', session: {})
end

describe 'callback error paths' do
it 'returns the failure response when the provider redirects back with error params' do
env = build_env('/auth/codebar/callback',
query: 'error=invalid_request&error_description=pkce+is+required+for+public+clients')
response = strategy.call!(env)

# A nil return here crashes Rack's TempfileReaper with `[]=' for nil`.
expect(response).to be_a(Array)
expect(response[0]).to eq(302)
expect(env['omniauth.error.type']).to eq(:auth_error)
end

it 'fails with csrf_detected when state is missing from session' do
env = build_env('/auth/codebar/callback', query: 'code=abc&state=some-state')
strategy.call!(env)
Expand Down
30 changes: 30 additions & 0 deletions spec/requests/omniauth_error_callback_spec.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
require 'rails_helper'

RSpec.describe 'OmniAuth provider error callback' do
# Regression: a provider error redirect (error=invalid_scope, pkce required,
# ...) used to crash the middleware stack with NoMethodError '[]=' for nil
# instead of redirecting to the failure page.
around do |example|
OmniAuth.config.test_mode = false
example.run
OmniAuth.config.test_mode = true
end

it 'redirects to the failure page instead of raising' do
get '/auth/codebar/callback', params: {
error: 'invalid_request',
error_description: 'pkce is required for public clients',
state: 'some-state',
iss: 'https://auth.codebar.io'
}

expect(response).to have_http_status(:redirect)
expect(response.location).to start_with('/auth/failure?')
end

it 'shows the authentication error flash after the failure redirect' do
get '/auth/failure', params: { message: 'auth_error', strategy: 'codebar' }

expect(response).to redirect_to(root_url)
end
end
Loading