Capybara session not preserved with an api callback - ruby-on-rails

I have a rail 5 app with capybara 2.13 feature specs. One spec completes a three-part transaction flow that includes a redirect url to a callback path in the app. I save the transaction ID in the session as session[:current_transaction_id] and then use this to look up the transaction when processing the callback. This works fine in development but when testing with capybara the session hash is missing :current_transaction_id.
I've unsuccessfuly tried wrapping my spec as described in
https://github.com/teamcapybara/capybara#using-sessions
Capybara.using_session("User session") do
# log in and complete a transaction
end
How can I get the session to persist through the given spec?

Capybaras using_session doesn't refer to the session you're asking about. It refers to a browser or browser/app pair instance used by Capybara and would commonly be used if you needed to simultaneously log two different users into an app while testing it (chat, realtime status updates, etc).
When using cookie based sessions you need to make sure the original (sub)domains originally being visited (where you set the transaction id) and the one redirected to are the same (at least to the level the session cookie is set at). If they aren't the session cookie will no longer be valid for the redirect request (and not sent) and hence the transaction id not available.

Related

Rails 4 session variable without a cookie

Because of the awesome EU directive on allowing users opt out from having cookies stored I have the following problem.
I have a message that displays at the top of the screen that asks the user to opt in or opt out.
if the user opts in, cookies are turned on using rack.policy, and the message is hidden. A cookie variable is set to say that the message should not be shown again for future visits. Perfect
If the user opts out. Cookies are disabled, fine. the message is cleared.... and a session variable is set to say don't show the message for this session. This would be fine, but it seems the session variable is saved in the same way as a cookie and the rack policy does not allow it to be displayed. The message therefore flashes up on every single page.
So first, thank you EU. Second, how do I save a "session variable" without saving to a cookie?
Unless you try going for something more exotic like local storage offered by the browser, you can't. The rails guide explicitly states:
All session stores use a cookie to store a unique ID for each session (you must use a cookie, Rails will not allow you to pass the session ID in the URL as this is less secure).
I'm no lawyer, but for what it's worth I believe that law is intended to apply to cookies used for marketing/tracking purposes and does not apply to cookies needed for the site to function like cookies used for authentication or ephemeral storage. With this in mind, you could use the rails's session cookie for must-have data and use separate cookies for other purposes that your application can disable.
I wouldn't take it as gospel, but this Wired article seems to a good job of providing a simplified explanation.

Integration Test with Transactional

I have the following scenario/system.
A Rest Service proposal, behind the Spring security configuration, with Spring JPA and a postgres DB.
Now my scenario makes a
login of a user 1
logout of user 1
login of user 1
make a request on a resource
logout of user 1
login of user 2
make a request on a other resource
logout of user 2
This all on a test method (I know it can be wrong doing that).
Now that was confusing me is that he had some encryption/decryption methods to retrieve user and they're fields. Now what I saw was that on the firs login of 1 the user goes through the decryption code (this is OK), after in the second login of user 1 we don't goes through the decryption code (but the user was logged in). (this is a little bit strange, I has expected that the user goes though the decryption code), after that by accessing the resource also user 2 is decrypted (this is correct).
But by logging in the user 2 the user don't pass on the decryption code (and I have an exception because the fields that normaly are encrypted, now are decrypted) The exception can be OK, but not the fact that the fields are decrypted.
Now the exception is thrown only when I set the test under #Transactional.
When I make the test not #Transactional then the behavior sames to be correct (evry time by login the user is decrypted.)
Now I think: "it is logical that the test does not be #transactional", but I have a bit fear that I have a caching problem: can this be? I dont'have any caching configuration (only for ACL, not for user management).
Also the second level cache of hibernate is turned off.
Is there a way to find out if some caching or inmemory strenght are intrcate?
Txs
Without seeing your actual code and configuration, I can't really assess exactly what is going on; however, I can provide you the following general information...
If you are simulating a use case that models different external connections to your application (i.e., two independent users connecting to your application via a REST API), then you will not want to annotate your test method with #Transactional.
Annotating a test method with #Transactional causes all of the method invocations within your test method to be executed within the same transaction [0]. Thus, any items stored in the first-level cache by JPA will be cached across method invocations within the scope of your test method.
Hope this helps!
Sam
[0] This statement is based on the assumption that none of the methods invoked directly or indirectly by your test method are configured to run within a new transaction.

Using session while sending set of AJAX requests

In my Rails application I make set of AJAX calls at once and that causes sending the same session cookie for each request.
The problem is that rails sets new session cookie in every response and therefore it expects that cookie value in the request after.
I'm looking for server-side solution because I don't want to chain those requests (they are time consuming).
Is it possible to change this behavior? And what security risks would come with it?
(I'm using Rails 4.1.0)
Many thanks
If the user doesn't already have a session cookie then there is nothing you can do.
If you can guarantee that the user already has a session (for example, if you require users to be logged in) then you may be able to do this with a server side session store.
With a server side session store the session cookie just contains an identifier - even if your overlapping ajax requests change values in the session they will not change the session cookie. In general this is better security wise: for example, old sessions can't be replayed after the user has logged out. Rails switched to the cookie store by default for performance reasons: no external data store needs to be accessed (however it does slightly increase the amount of data sent on each request)
Switching to a serverside session store isn't enough though and still leaves you open to race conditions. It is very easy to end up with a sequence along the lines of
Request A loads session
Request B loads session
Request B completes, saves session
Request A saves session and overwrites the session changes made by B
You need a session store that will attempt to merge any changes it has made with any changes that may have occurred from other requests.
I wrote such a session store some time ago. I haven't updated it for rails 4, since it isn't something i need anymore but you may be able to (or at least find inspiration in it)

Is it possible for Rails sessions to be created 'just in time'?

My understanding of the session lifecycle in Ruby on Rails (specifically v3 and upwards) is that a session is created at the start of a request, for each and every request, and if that request doesn't carry an existing session cookie a new one will be created, otherwise the session cookie is deserialized and stored in the session hash.
The purpose of this, of course, supports a number of security features such as CSRF etc.
However, this poses a bit of an issue when it comes to caching of pages in a site with HTTP cache services and proxies such as Varnish, as most of the configurations tend to strip out these (generally all) cookies on both the request and response end (as the cache is usually intended for a generalized audience).
I know that it is possible to setup Varnish etc to create the object hash with the cookie details included, and this would scope the cached data to that session (and therefor that user), however I am wondering if this is completely necessary.
I have an application which is fairly 'static' in nature - content is pulled from a database, rendered into a page which can then be cached - there are a few elements (such as comment count, 'recent' items etc) which can be added in with an ESI, but for every request Rails still tends to want to setup a new session, and when a user already has a session this stuff is stripped out by the cache server.
I am wondering if it might be possible (via pre-existing functionality, or building the functionality myself) to allow the developer to control when a session is required, and only when that is specified is the back-and-forwards with cookies, session initialization/deserialization etc necessary.
That, or I am thinking about this problem the wrong way and need to address the issue from another angle...
From what I know rails sessions can be controlled fairly in-depth via ActionController::SessionManagement
http://ap.rubyonrails.org/classes/ActionController/SessionManagement/ClassMethods.html#M000070
There are examples in the API docs of disabling it per action, per controller, etc.
If your site is mostly static then you may want to use full page caching. This takes Rails out of the request entirely and let's the web server deal with it once the content has been generated. Might cause some serious headaches depending on your exact needs as far as the comment counts and user-specifics though.

Implementing sessions in rails

I'm doing a first pass at rolling my own authentication and sessions in rails and am not sure that I understand the session support that is present. (By first pass, I mean I'm initially authenticating via http, not https. Production code will use https.)
My understanding of secure sessions is that you pass a token to the browser via a cookie over SSL, and then compare that token with the token stored on the server to see if it's really the user you think it is. I was hoping you guys could check my understanding of secure sessions, which is as follows:
User gets login page and submits login name and password (POST via SSL).
Server checks protocol and then checks sha1 of password (+ salt, usually) against existing hash in db. If they match, generate a session id, put it both in a(n SSL) cookie with the user id and in a server-side session store. Redirect user to the secured area of the site.
That session id remains the same throughout the user's logged in session --or-- the server issues a new session id after each secure operation, sending it via an SSL cookie and storing the new value in the db.
Any actions that involve private or secure data checks the session store for the existence of a session id for this user and, if present, compares the cookie's session_id against the session store before performing the action. If we're rotating session ids, issue a new session id (SSL cookie and server-side store) after the action.
User logs out, which tells the server to remove the session id from the session store and clear the cookie. Or the cookie expires on the browser and/or on the server and re-authentication is required.
Are there any glaring errors in the above? Also, it seems like Rails' session[] support wouldn't prevent MITM attacks if the token in the cookie was merely a session id. Is that correct?
I would suggest having a look at restful_authentication. This is the defacto standard auth library for Rails.
You don't actually need to generate the session_id yourself ... Rails handles all of this for you - checking the session id against the value provided by the browser. You can actually just store the user id in Rails session collection and then check that this exists.
You would technically be vulnerable to MITM attack if you do not use an SSL connection.
You seem to be confusing 'the session' and 'being logged in'. The session object in Rails is just a hash, stored in a cookie, and it is always present—regardless of whether or not the user has logged in.
As you outline, the most common procedure is to store the user's ID in the session.
The restful_authentication plugin does a lot of things. Perhaps you find my Blank Rails App more helpful, as it does something similar with a lot less code. Take a look at the sessions controller and lib/authentication, where the authentication related controller code is defined.
Try this web site, http://www.quarkruby.com/2007/10/21/sessions-and-cookies-in-ruby-on-rails. It appears to have a pretty comprehensive coverage of the subject.
One suggestion that I would have would be to not only use SSL but also encrypt and encode (Base 64) the session and other cookies that you send. Include a nonce (random value) with the session id so that the encrypted/encoded version changes every time you send it. If you are genuinely concerned about the session being hijacked you could also regenerate the session id periodically to limit the exposure of a hijacked cookie, although encrypting it should protected you if the cookies aren't persistent.
You should be able to use the encryption/encoding idea even if you use query parameters for the session id instead of cookies.

Resources