Devise throwing HTTP auth on XHR and logging out - ruby-on-rails

I'm having a ton of issues with Devise, using OmniAuth, to authenticate my Rails app. I relaunch my server and open up a new tab in Incognito mode (so that the cookies are cleared) and load my app. I log in, and then go through to the app.
When I get to a page that calls an authenticated action via AJAX, it asks for a username and password via HTTP Basic Authentication. I've disabled this in my devise.rb.
config.http_authenticatable = false
config.http_authenticatable_on_xhr = false
When I then go back to a previous page, it redirects me to the login page and asks for a login. This also happens when I visit a page that doesn't require authentication and then go back to an authenticated page.
This is getting immensely frustrating. I've unpacked Devise and Warden to my vendor/gems directory so that I can try to debug it, but I honestly can't figure out where to begin. Any help would be hugely appreciated.

Your AJAX call probably isn't setting the CSRF token. You might need to update your UJS gem (jquery-rails probably) or manually set the X-CSRF-Token HTTP header to the value of the tag. See this question: Devise session immediately expiring on .js call [AJAX]. You can test if this is the problem by disabling CSRF protection temporarily by chucking config.allow_forgery_protection = false in config/application.rb.
If you go the manual route, you should probably grab the value of the 'authenticity_token' meta tag first, and use that as the name of the actual token meta tag, rather than hard coding the reference to 'csrf-token'.
I would recommend updating to Rails 3.0.10 or 3.1 if you can. I was still having problems on 3.0.7.

Related

rails - What is the biggest security risk in intentionally disabling a CSRF check on the 'create' action?

I have a fully working product on Rails 5. I now wish to make a Chrome extension, using which users can create an 'Article'.
However, requests from my Chrome extension will be treated as Cross Site by my rails app. Hence, I was thinking of not doing the CSRF check at all on just my create action.
What is the biggest security risk associated with this? I understand after this, anyone will be able to make POST request to my server that creates a new article - however, this is not a damaging action like update, or worse, delete.
The Rails guide states that,
CSRF attack method works by including malicious code or a link in a
page that accesses a web application that the user is believed to have
authenticated. If the session for that web application has not timed
out, an attacker may execute unauthorized commands.
If a CSRF token is a valid one, it is a kind of assurance that the user session has not been hijacked and the request has been made with the user consent.
For more info, I recommend you to refer the Rails guide http://guides.rubyonrails.org/security.html#cross-site-request-forgery-csrf

Cookies without authentication ? (and cookie value)

I have a Rails app with Devise and was checking on front end if my Rails app was implementing cookies in order to comply with European rules regarding cookies.
I was a bit surprised as my Rails app actually add cookies to the client even without any Devise authentication ...
The cookie has name _myapp_session
Actually it is a good thing as I could add the cookie law information inside this cookie (user gets to see the cookie law warning only once)
...Yet each time I reload the root page in my browser the cookie is renewed.. So it doesn't actually look like a session cookie.
Is there a wrong setup in my initializer or can someone help me fix this ? (or maybe this is completely normal)
EDIT : Maybe my mistake : the cookie value is changing on every page yet the session creation time is not changing so I guess it is still valid to consider it a session cookie. I will search the web for a thorough explanation on cookies as the cookie value changing all the time is probably a feature.
Cookies are created by default in Rails Application.
Also, you're probably using Rememberable module in Devise which uses cookies.
Devise 'refreshes' csrf token after each request. Hence why it changes.
Did you try to look inside cookie and see what it contains?
Here's how you might do it (old rails version):
https://blog.bigbinary.com/2013/03/19/cookies-on-rails.html

Add middleware to Devise failure app [duplicate]

I use Devise for authentication and Apartment for multi-tenancy support on a SAAS app.
After a failed login, devise "redirects" to the login page (Users::SessionsController#new) and the value of Apartment::Tenant.current which was previously set in a TenantElevator middleware goes back to its default value of "public".
This is happening because Devise isn't actally redirecting to the login page but calling the FailureApp (which renders the login page) with a new rack env and returning its response. The new rack app doesn't have TenantElevator middleware so the tenant isn't set within the rack app.
Does anyone have any idea how to fix this? Maybe a way I can add the TenantElevator middleware to the Failure app?
Just stumbled on this and figured providing an answer may be useful for someone.
Haven't encountered this issue in a while, but looking through the sourcecode of the app I was working on, I fixed this issue by simply modifying where the apartment's middleware is inserted i.e modifying the order of the middleware.
Add the following snippet at the very bottom of your apartment.rb initializer file which should be located at app/config/initializers/apartment.rb
Rails.application.config.middleware.insert_before ActionDispatch::ShowExceptions, Apartment::Elevators::Domain
Essentially, insert your middleware before the ShowExceptions middleware, this ensures Devise, and ShowExceptions middleware, always runs under/within the context of the tenant set by whatever TenantElevator your app uses.
There may currently be a better way to handle this -- I am not sure, but this was the best option I found back when I had this issue.

Apartment current_tenant resets to 'public' after failed devise login

I use Devise for authentication and Apartment for multi-tenancy support on a SAAS app.
After a failed login, devise "redirects" to the login page (Users::SessionsController#new) and the value of Apartment::Tenant.current which was previously set in a TenantElevator middleware goes back to its default value of "public".
This is happening because Devise isn't actally redirecting to the login page but calling the FailureApp (which renders the login page) with a new rack env and returning its response. The new rack app doesn't have TenantElevator middleware so the tenant isn't set within the rack app.
Does anyone have any idea how to fix this? Maybe a way I can add the TenantElevator middleware to the Failure app?
Just stumbled on this and figured providing an answer may be useful for someone.
Haven't encountered this issue in a while, but looking through the sourcecode of the app I was working on, I fixed this issue by simply modifying where the apartment's middleware is inserted i.e modifying the order of the middleware.
Add the following snippet at the very bottom of your apartment.rb initializer file which should be located at app/config/initializers/apartment.rb
Rails.application.config.middleware.insert_before ActionDispatch::ShowExceptions, Apartment::Elevators::Domain
Essentially, insert your middleware before the ShowExceptions middleware, this ensures Devise, and ShowExceptions middleware, always runs under/within the context of the tenant set by whatever TenantElevator your app uses.
There may currently be a better way to handle this -- I am not sure, but this was the best option I found back when I had this issue.

How to handle pages with stale CSRF authenticity tokens in Rails

In our Rails application, it is common for users to keep multiple browser tabs open for hours or days at a time. The problem occurs when in one of these tabs, the user logs out then logs back in (or the session expires and a new session is created).
This causes the CSRF authenticity tokens on all the other tabs to become invalid. If they try to submit any form or make any ajax request on those tabs without refreshing, they will get an error (and in fact get logged out because that is the default Rails behavior when a bad authenticity token is passed).
This behavior is clearly undesirable. I was wondering what people do to gracefully handle situations where a user has a window open to your site but the authenticity token is out of date.
What I don't want to do is just redirect them to the login page, because then they might lose their work, if for example they have been writng a long blog post or something.
The solution that comes to mind is to have some javascript that either polls the server to check whether the authenticity token has changed, or polls the user's cookies to check whether the session has changed. I have never heard of anyone doing either of these, so I wanted to see what the community thought.
First of: logging in/out/in won't lead to appearing a new csrf-token. It still will be saved in the user's cookie. Next time it logs in via the same browser it'll get the same token.
In latest versions of Rails no errors will be thrown in the case of incorrect token: all the Rails does -- just resets the session before passing it to a controller.
So, update your Rails and you'll get one pain less.
Are you sure you are talking about CSRF token and not session token? It does not make any sense at all to redirect to login on a CSRF token mismatch. You just tell the user to repeat whatever he tried to do. (In a traditional web application this typically comes up when a form is submitted; you can treat the CSRF mismatch as a validation error, and show the form again, keeping all the field values, and ask the user to resubmit. In a more AJAX-heavy application you can use some sort of generic CSRF flag in the response, and if it is set, ask the user to do whatever he did (press the button etc) once more, or even automate the whole thing without bothering the user.

Resources