Rails cookie based sessions: mixing session scope with expiration times - ruby-on-rails

So I've asked this question in a different way here and got no answers so I'm going to try to rephrase it, since this seems to be a very simple issue.
I have a Rails app with cookie based sessions. By default they don't have any expires_at timestamps and so the scope of the session cookie is 'session'. This is your vanilla Rails sessions stuff.
Now I want to create a 'demo user' functionality wherein I kick the user out after 15 mins. To accomplish this, I want to set an expires_at on the session cookie for Time.now + 15.minutes
session[:expires_at] = Time.now + 15.minutes
Now this above piece of code does execute, but it has no impact on the cookie's scope. The scope remains 'session'. How do I change the scope from being 'session' to being a datetime?
If I configure my entire application's Session in the production.rb to be
:expire_after => 24.hours
Then it will work... but the problem is that I want to selectively control the expiration date on the session cookie.
Edit: Turns out that the reason why there is no impact on the cookie's scope when I set the session[:expires_at] is because subsequent requests are clobbering the session cookie and resetting it back to session. Still not sure what to do about it.

Perhaps instead of relying on cookie expiry (see section 2.9 in "Ruby On Rails Security Guide" on why it is bad), similar to this answer, store timestamp when session was created in the session itself (say session[:created_at]) and then check on each request if it needs to be expired for these 'demo users':
before_filter :check_session
def check_session
# TODO: check session validity
if session[:demo_user] && session[:created_at] > 15.minutes.ago
reset_session
# TODO: redirect to login page
end
end

While not the very elegant way, but this works for a single session:
...
request.env['rack.session.options'] = {expire_after: 15.minutes}
session[:user_id] = 1
...

Related

How to set cookie without encryption [Rails] [duplicate]

How do I set a Rails cookie to start and/or expire at a certain date?
Excerpts from Rails 5 documentation:
Cookies are read and written through ActionController#cookies.
The cookies being read are the ones received along with the request, the cookies being written will be sent out with the response. Reading a cookie does not get the cookie object itself back, just the value it holds.
Examples of writing:
# Sets a simple session cookie.
# This cookie will be deleted when the user's browser is closed.
cookies[:user_name] = "david"
# Sets a cookie that expires in 1 hour.
cookies[:login] = { value: "XJ-122", expires: 1.hour }
# Sets a cookie that expires at a specific time.
cookies[:login] = { value: "XJ-122", expires: Time.utc(2020, 10, 15, 5) }
# Sets a "permanent" cookie (which expires in 20 years from now).
cookies.permanent[:login] = "XJ-122"
[...]
The option symbols for setting cookies are:
:expires - The time at which this cookie expires, as a Time or ActiveSupport::Duration object.
[...]
your question might be related to this question:
How to I dynamically set the expiry time for a cookie-based session in Rails
one of the comments points to Deprecating SlideSessions:
"..If you need to set expiration period
for sessions through all controllers
in your application, simply add the
following option to your
config/intializers/session_store.rb
file:
:expire_after => 60.minutes
If you need to set different
expiration time in different
controllers or actions, use the
following code in action or some
before_filter:
request.session_options = request.session_options.dup
request.session_options[:expire_after]= 5.minutes
request.session_options.freeze
Duplication of the hash is needed only
because it is already frozen at that
point, even though modification of at
least :expire_after is possible and
works flawlessly..."
I hope that helps. :)
It's worth noting that as of right now it is impossible to set a start time for a cookie. A cookie set is always active immediately.

Rails 3 session & cookie how to persist session id cookie

I am developing a simple shopping cart based on session_id i.e. for determination of a user cart items used session_id.
But when user closes a browser and then opens it again a session id is been changed. And he loses all his items in cart.
I suspect such feature I can provide with saving session id in cookie.
Am I right?
Any way my question is How to provide a functionality that allows users get their cart items even after closing a browser?
I recommend reading the Rails Guide: Action Controller Overview (http://guides.rubyonrails.org/action_controller_overview.html).
Sections 4 and 5 cover Sessions and Cookies and will give you a deeper understanding
on how to use them and will make it easier to tackle future challenges.
I would also check out the Ruby on Rails ActionDispatch::Cookies < Object Documentation
(http://api.rubyonrails.org/classes/ActionDispatch/Cookies.html)
An example of the controller code you are looking for is listed on this resource. Here is an example:
# Sets a cookie that expires in 1 hour.
cookies[:login] = { :value => "XJ-122", :expires => 1.hour.from_now }
cookies[:your_cookie] = {
:value => "your_cookie_value",
:expires => 100.years.from_now
}
for more details, check it out.
Rails stores the session in a cookie by default. You can influence if
the cookie lives beyond a restart of the browser (see below).
Cookies ARE NOT shared between browsers. Ever.
If you want to use Opera to look at the shopping cart you just created in Firefox you need to authenticate to the shop in some way, for example with username and password.
See Rails 3 additional session configuration options (key, expires_after, secure) for a description of all the configuration options for your session.
you'll be wanting to look at :expire_after, for example
:expire_after => 24.hours
(Found here: Setting session timeout in Rails 3)

How to handle the expiration of login cookies if a user is inactive for more than a set time using Ruby on Rails?

I am trying to manage the login session of users that navigate in my RoR3 application.
I set a cookie when they sign in and I would like that their authentication expires after a few minutes of inactivity, for example 15 minutes.
How to achieve that?
This doesn't directly answer your question, but I strongly suggest using something like Devise for authentication instead of rolling your own.
Devise provides a timeoutable configuration flag, as well as a timeout value covering how long user sessions can be inactive before being logged out.
You could setup a property in your session. Something like
session[:expire_time] = 15.minutes.since
Then, in your applicationController you can check if your user has been away enough time to be logged out, if not then you renew his expiration time, something like:
class ApplicationController < ActionController::Base
before_filter :check_expire
def check_expire
if session[:expire_time] and session[:expire_time] < Time.now
#your code to logout the user
else
session[:expire_time] = 15.minutes.since
end
return true
end
end
You can also set the expiration time of the cookie that sets their session. In your configuration :
env["rack.session.options"][:expire_after] = 15.minutes
This works perfectly for the use case you described, because it will be reset every time the server responds, but it gives you a little less control.
Here's a good article about it :
http://augustl.com/blog/2010/dynamic_session_expiration_time_in_rails_3

Set start date and expiration date for Rails cookies

How do I set a Rails cookie to start and/or expire at a certain date?
Excerpts from Rails 5 documentation:
Cookies are read and written through ActionController#cookies.
The cookies being read are the ones received along with the request, the cookies being written will be sent out with the response. Reading a cookie does not get the cookie object itself back, just the value it holds.
Examples of writing:
# Sets a simple session cookie.
# This cookie will be deleted when the user's browser is closed.
cookies[:user_name] = "david"
# Sets a cookie that expires in 1 hour.
cookies[:login] = { value: "XJ-122", expires: 1.hour }
# Sets a cookie that expires at a specific time.
cookies[:login] = { value: "XJ-122", expires: Time.utc(2020, 10, 15, 5) }
# Sets a "permanent" cookie (which expires in 20 years from now).
cookies.permanent[:login] = "XJ-122"
[...]
The option symbols for setting cookies are:
:expires - The time at which this cookie expires, as a Time or ActiveSupport::Duration object.
[...]
your question might be related to this question:
How to I dynamically set the expiry time for a cookie-based session in Rails
one of the comments points to Deprecating SlideSessions:
"..If you need to set expiration period
for sessions through all controllers
in your application, simply add the
following option to your
config/intializers/session_store.rb
file:
:expire_after => 60.minutes
If you need to set different
expiration time in different
controllers or actions, use the
following code in action or some
before_filter:
request.session_options = request.session_options.dup
request.session_options[:expire_after]= 5.minutes
request.session_options.freeze
Duplication of the hash is needed only
because it is already frozen at that
point, even though modification of at
least :expire_after is possible and
works flawlessly..."
I hope that helps. :)
It's worth noting that as of right now it is impossible to set a start time for a cookie. A cookie set is always active immediately.

How to I dynamically set the expiry time for a cookie-based session in Rails

I'm currently using the ActiveRecord-based session store for my Rails app and I have a background process which clears out inactive sessions every 30 minutes.
I'd like to switch to Rails' new cookie-based session store but how do I set the expiry time of the session to 30 minutes, as opposed to the default 'at end of session' value?
I stumbled across this question after a conversation in the office. Just for the sake of completeness, I've discovered that it is possible to expire sessions after a period of inactivity and it's built into Rails. In config/environment.rb, do something along the lines of:
config.action_controller.session = {
:key => 'whatever',
:secret => 'nottellingyou',
:expire_after => 30.minutes
}
Check out lib/action_controller/session/cookie_store.rb#114 for the (apparently undocumented) option in action. Looks like it's been around since the move to Rack sessions back in December 2008.
Ideally, you'd want to add something like this to environment.rb:
session :session_expires => 1.day.from_now
But that won't work because the code is only run once when the APP is started and thus the next day all your sessions are being created with an expiration in the past.
I usually set the session_expires to some time far in the future (6 months). Then manually set and check a session[:expires] date in a before_filter on my application controller and reset the session when that date has passed.
This makes it VERY easy to add a 'Keep me logged in for ___' option when signing in, you just set session[:expires] = Time.now + ___
After a lot of pain & experimenting, found in Rails 3.x, you need to set your custom session parameters in an after filter in every request
class ApplicationController < ActionController::Base
after_filter :short_session
...
def short_session
request.session_options = request.session_options.dup
request.session_options[:expire_after] = 1.minute
request.session_options.freeze
end
The session options page on the Rails wiki hints that this is only possible through a plugin:
Set the session cookie expire time
Unfortunately Rails has no way to dynamically set the expiry time of the session cookie. So it is recommended that you use the following plugin, which allows you to accomplish it: http://blog.codahale.com/2006/04/08/dynamic-session-expiration-times-with-rails/
Of course take into account that the plugin is old, and may not work with your current version of Rails (I haven't looked at the specifics)
Use this, it's working for me in rails 2.1.x:
SlidingSessions
I currently have cookies set to expire exactly 2 weeks after a user logs in, and setting it to 30 minutes is simple.
You could try adding the following line to your environment.rb file:
session :session_key => 'my_session_key'
session :session_expires => 1.day.from_now
Alternatively, you can set the session options as follows:
ActionController::Base.session_options[:session_expires] = 1.day.from_now
I've not tested this thouroughly, so YMMV.

Resources