I have a Rails 4.2 application. Several months ago we started experiencing Invalid Authenticity Token errors. I've discovered that the following scenario reproduces the error:
1) User opens up browser and visit's ourwebsite.com/log-in.
2) User opens up second tab in the same browser and visits ourwebsite.com/enroll-in-course.
3) User goes back to tab one and logs in submitting a POST form.
4) User goes to tab two and submits a POST form on the enroll-in-course page.
5) Error appears.
Here's some general information about our app:
We are using Devise 3.4.1 with zero customization applied.
Our application controller runs protect_from_forgery with: :exception.
We use Turbolinks 2.5.
We are not caching either forms.
We run Turbolinks.pagesCached(0); in our Javascript on all pages.
To reiterate, both forms in the above scenario are POST forms. They work perfectly fine except in the above scenario.
From my knowledge, we have not made any changes in handling user sessions or CSRF tokens.
I have a theory that because we log in the user, the csrf_token stored in the session changes. Thus when the user submits a form in the second tab, the token from form will not match the token in the session and an InvalidAuthenticityToken is raised. What's wrong and how do I fix this? Better yet, is this even fixable?
Related
So I am developing a Rails application with LinkedIn authentication. The application works fine in all the cases except the case when user cancels the login.
I have already visited all the solutions on this site could possibly help, but no luck.
I have designed a very basic login structure and I couldn't understand where to write the code to handle the exception and to redirect the failure to a particular path.
The process I have used to make my login page was: Adding gem, Adding a route to 'auth/linkedin/callback', Adding that controller, Adding omniauth.rb file with provider, client id, key, scope and fields parameters.
Adding from_omniauth method in user model.
And finally the link in view page. Here I have no idea what to manipulate to handle the params error. Thanks
error
This Rails project uses Spree and Devise and has a separate controller to serve up JSON responses for the mobile side of things. I've just implemented Devise::Lockable to lock a user account after 5 failed logins. This automatically generates a password reset email. Things work fine on the desktop site and on the mobile site. My question comes from mixing the two together:
If you fail login 5 times through mobile API, the password link is sent to that account's email. But if you are already signed in on the desktop, and then also access the reset link from the desktop, it redirects to the home page (and signs out the user). If you click the reset link again, then the password reset form is served up.
How can I also sign out a user on from "normal" app (the desktop side of things) when the user fails logging in the maximum times on the mobile app?
EDIT: I've tried throwing Devise's "sign_out user" at almost every point in the pipeline but that doesn't do the trick, since the user for some reason isn't found to be signed in.
I've been around the houses on this and I'm sure I'm approaching this the wrong way.
On my RoR site, users can enter details for a new post if they are logged out. But when they hit 'Create' I check if they are authenticated or not. If they are not, I ask the user to log in or create an account. Once logged in, I want the form to resubmit automatically with the original POST data. I'm using devise for authentication.
I have everything working, except retaining the original form POST data and avoiding a CSRF fail.
I think the CSRF fail is because the resubmitted data does not have the authenticity token - so I've turned off CSRF protection for now, until I fix the
POST data retention.
I can't store the data in the session as the form data includes an image and breaks the 4k session limit.
Please, is there a regular Rails pattern that solves this problem?
Thanks
Paul
It's simple: take authenticity token from new form (which you re-request after user logs in) and send it with the old request data.
I know how to implement a spring security login form the "classical" way, but I'm having a hard time figuring out how to implement a login form that opens in a modal and always behaves "properly".
It is not as trivial as it sounds.
Here are my specifications:
when an unauthenticated user requests a protected page, a modal login form should appear; when the login is successful, the requested page should appear and the address bar should display the requested url as in a non-modal approach
when this is triggered from outside the site, the modal should open on the site home page
when this is triggered from inside the site, the modal should open on the current page
when a user clicks on a "login" button on the site header (from any unprotected page) a modal login form should appear without changing page; when the login is successful, the location should not change but the page should be reloaded in order to be updated (e.g. showing the user name in the header)
if the modal is closed before submission, the original page should not have changed
if there are login errors, they should appear in the modal without redrawing the whole page
if the login form is submitted after session expiration, the login process should handle expired CSRF tokens gracefully (but I might consider removing them altogether for the login form, where I don't think are needed anyway)
every ajax request on the site (that originates from a protected page), should handle login requests gracefully
brute-force attacks should be hampered by temporarily suspending a username after some failed attempts
Java-only Spring configuration (no XML) and JQuery
the logout link should not trigger an authorization error when the session is expired
We have a Rails 3 app using session-based authentication (modified acts_as_authenticated), and a Flex app that needs to be embedded in an html.erb template. The Flex app needs to access routes that have a before_filter set to check if the user is logged in. When interacting with the HTML site, this causes the user to be redirected to a login page, then sets a Rails session property (tied to a cookie) to record that the user is logged in when making future requests.
The Flex app needs to access XML that's generated by Rails (behind the before_filter) and I don't want to force the user to log in twice -- what should I be passing as a flash parameter to the Flex app so that it can present as "already logged in" if that session exists (ie, the user has logged in via the HTML interface)? I haven't dealt with this kind of problem before so I'm not sure if I'm even asking the right question. Any advice appreciated!
Integrating flash into your authenticated service can be tricky. You can't rely on normal http sessions or cookies to manage authentication for you. What is generally regarded best practice is to generate a unique token for each logged in user to pass on every request to the server to prove that they are in fact a logged in user. for example:
They log in through an html form.
When you serve up a swf that is going to access authenticated content you give it a flashvar of token=49r03f0239fhduffnkdjfgnas or something like that.
This token is generated server-side and stored somewhere to be checked on requests.
On every request to the server you pass this token and check it's validity.
If it's good you perform the action and return the data.
If it's bad you prompt the user.
notes:
tokens should be long and unguessable like a session variable.
each time they log in you need to generate a new token.
each time they log out you need to destroy the token.