Flash message does not get cleared - ruby-on-rails

Using Rails 3.0.3 running in Passenger we're experiencing an issue where the last flash set is retained for every request. For example we're setting a flash message if the user needs to be logged in in a before filter:
def require_user
unless current_user
store_location
flash[:notice] = "You must be logged in to access this page"
redirect_to login_url
return false
end
end
However on any subsequent request after the user has logged in successfully we still get the flash message persisting, it never clears for the entire session.
In this example this is the only place we are setting this message and I have ensured that it is only being set when the user is not logged in. In fact if I put flash[:notice] = 'Test' after the unless block refreshed and then removed that line and the 'Test' flash message remains for all subsequent requests.
This is happening if you run the app in either development or production env.

We had a custom override for Hash#symbolize_keys! that was hanging around from some old code and it appears that when the cookie middleware is calling symbolize_keys! on the cookie it was causing the flash to be re-applied on the end of the request.
I doubt anyone else will experience this issue, but in our case this is what the problem was.

Flash messages are automatically cleaned up at the beginning of each request.
Are you sure, your current_user method returns nil if user is not logged in ?
What library are you using for user session management ? Devise/Authlogic or other ?

Related

Rails Devise Login Sometimes Does Not Redirect

I have a rails app configured with devise and it works most of the time. Signup seems to have no issues at all.
Sometimes when trying to login an existing user (the same test user I've successfully logged in many times) The page does not redirect.
When I check the logs I see it logging that the redirect was successful. And if I refresh the page then I'm logged in. I haven't been able to reliably recreate the issue but it seems more likely to happen when the server is restarted.
I updated the redirect code to this:
def after_sign_in_path_for(resource)
current_user.sync_with_crm
current_user.save
return stored_location_for(resource) || root_path
end
The current_user.sync_with_crm makes an api call to my CRM and then sets some associations that I need to save on the user model. I don't know how this could be the issue as it does work most of the time.
Not even sure how to trouble shoot this further.
ruby 2.5, rails 5.2.0, devise 4.4.3

How current_user works in devise rails

I have been using the devise gem for authenticating my rails app for some time now, and I just began to wonder how the current_user works
How does devise saves the current_user?
Browser session?
Application session?
Some other parts of the Application?
I am suspecting that the answer is number one Browser session. Reason being that even when an app gets restarted, and you try to access the app again from a browser that has been used to sign in already, it automatically signs you in.
My confusion though is this: If it is the browser session, it means that when the browser relaunches ( the session was ended ) current_user should be expired, and the user signed out; but it does not work so.
So, how does the current_user operates? thanks for all contributions.
current_user works by storing id of current user in the application session. Most commonly session is stored in cookies. Whether or not the cookies survive browser restart depends on client's browser settings.
If you have clicked remember_me it stores a signed token unique to user in a permanent cookie and stores it in browser. It is saved in database also.
When current_user is called again , rails checks if the permanent cookie exists, if so compares it with the one in database. If they are the same , you are logged in as that user.

Testing behavior of post request for non-logged in user

I'm working on a project where users login and out, a complete shocker I know, and we're ensuring that people can logout when done. One thing we've noticed is that for various reasons a user can try to click the logout button when the system have already logged them out. (Session timeout, logged in from another browser, or other reasons. The site only allows for one concurrent login per user.)
So what happens when the user tries to POST to the logout URL is that they fail a CSRF validation, since they don't have a valid session. We can't remove the CSRF validation because of security concerns.
As such I'm trying to add a test that allows me to test this behavior and so that instead of blowing up with an invalid CSRF token it'll silently accept that the user is already logged out and continue on with its business.
What I've tried is basically this:
context 'user is not logged in' do
before do
Rails.application.config.action_controller.allow_forgery_protection = true
end
it 'does not blow up' do
expect { post :destroy, {}, { some_key: 'val' } }.not_to raise_error
end
it 'redirects to logout path' do
expect(response).to redirect_to(successful_logout_path)
end
end
Which goes green despite not having had any logic changes in my controller, and manual testing confirms it's still not working.
Any suggestion for how to enable the CSRF validation for this context, or another way of testing this in the unit tests?
Devise was having a similar problem up until last year. I submitted an issue on Github here: https://github.com/plataformatec/devise/issues/2934 and it was eventually fixed. This other question should give you a hand: InvalidAuthenticityToken in Devise::SessionsController#destroy (sign out after already having signed out)

ROR user authentication

In my web app after a user logs in a new session is created so until he closes the browser he stays logged in. The problem appears when admin wants to ban the user who's browser is still open. Even though the user is banned and cannot log in anymore, he still stays logged in until he closes the browser or manually logs out. This definitely should be fixed.
Is it possible to add a verifying method to every action of every controller? Of course I mean a smart way - not copy/paste 100 times.
add the following to your application controller:
before_filter :sign_out_banned_user
def sign_out_banned_user
if current_user.banned?
session[:current_user_id] = nil
redirect_to root_path, :notice => "You are banned"
return false
end
end
You must reset the session also i think.

Check FB Connect session expire using facebooker

how to check whether FB Connect session is still valid or not using rails facebooker plugin ? Are there any helper or module that can check the session ? I figure out that if I open up 2 tab in browser, one login with facebook, another is with my site and login using FB Connect. When user trying to logout in my site, facebook will erase both cookie, but when user logout through facebook, it will erase cookie in facebook site only, so the cookie in my site still left behind and I need to check whether the cookie still valid or not...
Using Facebooker, you'll get an exception when you try to use the exception, which can be rescue_from'd in application.rb
rescue_from Facebooker::Session::SessionExpired, :with => :facebook_session_expired
def facebook_session_expired
clear_fb_cookies!
clear_facebook_session_information
reset_session # remove your cookies!
flash[:error] = "Your facebook session has expired."
redirect_to root_url
end
I can't upvote things yet, but the answer that adds the line:
page.redirect_to url
is correct. I'd recommend adding it to Facebooker if Mike is reading.
The fb_logout_link method does not redirect when Facebook session is invalid. Add a redirect callback to your logout_path and it will do the job for you.
def fb_logout_link(text,url,*args)
js = update_page do |page|
page.call "FB.Connect.logoutAndRedirect",url
# When session is valid, this call is meaningless, since we already redirect
# When session is invalid, it will log the user out of the system.
page.redirect_to url # You can use any *string* based path here
end
link_to_function text, js, *args
end

Resources