omniauth icon indicating copy to clipboard operation
omniauth copied to clipboard

Unable to test auth failure when test_mode is true

Open Epyon616 opened this issue 12 years ago • 8 comments

I've been playing around with the latest version of Omniauth and its various strategies, and I have come across a rather annoying issue. When I have test_mode set to true in my spec_helper and I am trying to test authentication failures, the authentication callback is always coming back as successful.

For example I have an acceptance test to check that if a user tries to log in using Identity but does not fill in the password field, they should see the authentication error. when I try this in my browser I get the expected outcome, however when I run my spec for this it is always logging in the user even without a password. I have verified this by changing the email address the test users to try and log in.

Yet if I turn test_mode off, all the tests I have pass as expected.

Am I using Omniauths test_mode in the wrong manner or is there a way of acceptance testing with it set to true that means I can actually test what happens when someone tried logging in with invalid credentials.

Epyon616 avatar Dec 21 '12 10:12 Epyon616

I've got something similar with the identity strategy, manifesting as /auth/identity/register returning a 404. Turning off test mode fixes, but it's kind of a pain, since test mode needs to be ON to mock social auth.

stephenprater avatar Jan 01 '13 22:01 stephenprater

thats exactly what I get, its almost as though you should be adding extra routes to your routes file just for testing which seems a little off to me.

Epyon616 avatar Jan 01 '13 22:01 Epyon616

Worked around it by adding this middleware to my stack right before OmniAuth::Builder pretty hacky, but it makes it work. I'm not sure if there's a better way to do this or not.

class OmniAuthMockEnable
  def initialize(app)
    @app = app
  end

  def call(env)
    if env['PATH_INFO'] =~ /identity/
      test = OmniAuth.config.test_mode
      OmniAuth.config.test_mode = false
    end
    @app.call(env)
  ensure
    OmniAuth.config.test_mode = test
  end
end

stephenprater avatar Jan 02 '13 15:01 stephenprater

I was having an issue when I was using: OmniAuth.config.mock_auth[:identity]

When I switch to: OmniAuth.config.add_mock(:identity, :invalid_credentials) it at least started working, but it is successful every time regardless of setting it to fail.

revans avatar Jan 12 '13 00:01 revans

Same issue. Right now i am not able to test failure endpoint. The mock auth OmniAuth.config.mock_auth[:facebook] = :invalid_credentials is ignored and always redirect to the auth/facebook/callback phase. Using OmniAuth.config.add_mock(:facebook, :invalid_credentials) raise an error because it expects an Hash instead of a Symbol Testing with browser in development env it's ok. This issue is really annoying because it's impossible to have a complete test. The only different thing i see from other examples is that I am using the setup phase because i need to manage different social apps. Are you using setup phase or it is an independent behaviour?

marqu3z avatar Oct 08 '13 10:10 marqu3z

I currently have the same problem in test mode. OmniAuth.config.mock_auth[:twitter] = :invalid_credentials is ignored and the failure endpoint is never used. Switching test_mode to false does not help though. Has anybody found a solution to this?

matthieu80 avatar Apr 09 '18 07:04 matthieu80

I will take a seat here.

Papipo avatar Apr 13 '18 13:04 Papipo

I have just encountered this problem and I was able to trace it to the following lines:

https://github.com/omniauth/omniauth/blob/fce9e23dd4ed33c275485a43b9cc18c1412db9a9/lib/omniauth/strategy.rb#L299-L307

as you can see if you mock the "invalid credentials" scenario with

OmniAuth.config.mock_auth[:twitter] = :invalid_credentials

the code will call fail! with :invalid_credentials as a param. fail! is defined as:

https://github.com/omniauth/omniauth/blob/fce9e23dd4ed33c275485a43b9cc18c1412db9a9/lib/omniauth/strategy.rb#L480-L492

which accepts an optional exception which is never passed.

Also, the setup code above never calls OmniAuth.config.before_callback_phase so there's no way you can prepare env['omniauth.error'] or the other variables before hand (which would be overridden anyway).

BUT

if you look closely, the last thing fail! does is call OmniAuth.config.on_failure.call(env) so I thought to myself: "maybe there's an opportunity there".

I ended up with something like:

OmniAuth.config.mock_auth[:twitter] = :invalid_credentials

global_failure_handler = OmniAuth.config.on_failure

local_failure_handler = proc do |env|
  error = OmniAuth::Strategies::OAuth2::CallbackError.new(
    "Callback error", "Error reason", "https://example.com/error"
  )
  env["omniauth.error"] = error
  env
end
# here we compose the two handlers into a single function,
# the result will be global_failure_handler(local_failure_handler(env))
failure_handler = global_failure_handler << local_failure_handler

OmniAuth.config.on_failure = failure_handler

visit path
# check stuff

# set `OmniAuth.config.on_failure = global_failure_handler` when you're done

hope it helps someone!

rhymes avatar Apr 08 '20 09:04 rhymes