Search code examples
ruby-on-railsruby-on-rails-3authenticationdevisewarden

Devise preserve original path during sign in


I have a case where two requests(iframes) are made by browser to a rails app (rails 3.2, devise 2.2.0), both initiate sign in (through SSO) and then render the requested page. Problem is that there is a race condition for session[:user_return_to] and both of the pages render same page so one of the iframes end up rendering wrong page.

This is the flow of the app right now

  1. authenticate_user! method is called and devise redirects to /users/sign_in page
  2. SessionsController#new processes the request and instead on rendering it redirects to /sso/new
  3. Request comes back in from SSO to /sso/create which sign user in (in devise) and redirects to requested page

On step 2, I can pass a URL as a param to /sso/new and that param will be returned back to me during step 3. Problem is that referrer is already lost when I'm in SessionsController#new. All I have there is session[:user_return_to] which already has wrong value for one of the iframes (session is shared and race condition occurs).

I was wondering if the referrer can be passed on somehow through warden failure. I was not able to see if there is a hook to pass it as param or header through warden when executing authenticate_user! before filter. During that request I have referrer but warden doesnt preserve it when it redirects to /users/sign_in.


Solution

  • I was able to solve this problem by using custom failure app for warden.

    I used request.original_fullpath in redirect_url and it worked.

    here is my failure class

    class CustomDeviseFailure < Devise::FailureApp
      def redirect_url
        if sso_enabled?
          sso_path(return_to: request.original_fullpath)
        else
          super
        end
      end
    
      def sso_enabled?
        true
      end
    end