How maintain users authentications\sessions through multiple application? - ruby-on-rails

I am using Ruby on Rails 3 and I have 3 web applications:
<site_name>.com
users.<site_name>.com
resources.<site_name>.com
Notice: At this time I have applications on the same server, but in future I can choose to deploy those on separated web servers. So, I would like not use the common solution:
config.session_store :cookie_store, :key => '<whatever key>', :domain => :all
Consider this in your answer.
I would like to handle user authentications\sessions through all those applications so that a user must authenticate himself only one time. That is, I would like to sign in a user on users.<site_name>.com and then maintain its session on browsing other applications.
So, question are:
What do you advice in order to implement these functions? Do that writing own code or using gem(s)\plugin(s)? If the latter, what gem(s)\plugin(s) combination do you advice to use?
I have heard of the OAuth protocoll: in my case (also if at this time I need to authorizate users only through my applications) is it right to use that? If so, what gem(s)\plugin(s) can I use to achieve that?

If you're always going to have these servers on *.<site_name>.com then you could use a cookie written to the <site_name>.com scope to track and authenticate this user. Obviously you do have to be careful about this and make sure that a) the cookie is transferred via HTTPS (secure cookie) and that b) that each server validates the cookie via some sort of web service.
I suggest looking into Warden and the warden_rails gem. On top of this basic well documented authentication foundation you can write "strategies" to validate users using a cookie and read in the session information from a central datasource.

if they all run under the same domain the easiest would be to make sure your cookies are valid for all subdomains. in your production.rb:
config.session_store :cookie_store, :key => '<whatever key>', :domain => :all
the :domain => :all causes your cookies to be valid across all subdomains. just make sure the key and also your session secret token are the same in all apps.

Related

Rails ActiveRecord Session Store in HTML5 SessionStorage Instead of Cookie

My application has a requirement for users to log into different accounts in separate tabs in their browser (we target Chrome specifically). Because Rails uses cookies to store session info, when the user is logged in, they are logged in on all tabs in the browser. I'm using the ActiveRecord session store method, but even the ID for the session is saved as a cookie.
It seems there's a solution in using HTML5's sessionStorage mechanism, which is limited in scope to the tab or window that the user is logged into. It seems all I have to do is direct Rails to save the session info into the sessionStorage rather than cookies. But I can find no information on this at all.
Assuming there's no way to configure the session store to do this in Rails, is it possible to override the ActiveRecord session saving mechanism? Any pointers on where to look for info about how to go about this?
Unlike cookies, sessionStorage entries cannot be created with response headers, and are not automatically included in request headers. This puts a lot of the workload for managing sessionStorage/localStorage-based authentication on client-side Javascript. All authenticated access would have to be through Javascript XHR requests which explicitly include the authentication token.
If you want the user to be able to have several concurrent sessions, and you don't want to build your site as a SPA, then you will have to take an alternate approach with cookies.
One way would be to use multiple domains to force the cookies into separate subspaces. Set a wildcard DNS record and configure your web server to accept all matching requests regardless of prefix. For example, users might by default be at www.yoursite.com. You would provide a 'create new session' link which opens a new tab to a random subdomain, e.g. 1234abcd.www.yoursite.com. This may create a problem if you are using SSL, however; wildcard SSL certificates tend to be much more expensive.
A simpler way would be to educate users about their browsers' private/icognito modes, which maintain independent cookie stores. However, getting users to read documentation is always a challenge.
You now configure the Cookie-based session store through an initializer, probably in config/initializers/session_store.rb. In Rails 3 the session store is a piece of middleware, and the configuration options are passed in with a single call to config.session_store:
Your::Application.config.session_store :cookie_store, :key => '_session'
You can put any extra options you want in the hash with :key, e.g.
Your::Application.config.session_store :cookie_store, {
:key => '_session_id',
:path => '/',
:domain => nil,
:expire_after => nil,
:secure => false,
:httponly => true,
:cookie_only => true
}

Sharing session across rails apps on different subdomains

I am trying to implement a single-sign-on solution for multiple rails (v3.2) apps hosted at different subdomains of example.com
One app serves as an identity provider, uses devise for auth, and sits at users.example.com
The other apps rely on the identity provider for authentication, use devise+omniauth, with domains of [app1.example.com, app2.example.com, and example.com].
This blog entry inspired much of my implementation: http://blog.joshsoftware.com/2010/12/16/multiple-applications-with-devise-omniauth-and-single-sign-on/
I have it working fine, but the problem remains that the sessions are not shared so after I log in on the identity provider, I still have to make a call from each of the other apps to authenticate and I need this to be seemless to the user.
I tried using the same secret token at secret_token.rb, same session key at session_store.rb and :domain => :all (also tried '.example.com' and 'example.com' as values). Still no luck.
Doing the above, I see in a session.inspect that after login on the identity provider the session variable "warden.user.user.key" is populated. When I immediately go to the app on app1.example.com, the session.inspect shows the same session_id and _csrf_token but the "warden.user.user.key" variable is now missing.
I feel like I am missing something silly.. Any ideas what that may be?
I think there is another SO question about getting a single cookie to work across subdomains that would answer yours:
https://stackoverflow.com/a/10403338/2573896
Also, I can imagine that using a memcached cluster with dalli and memcached as your session store would work as well:
http://awesomerails.wordpress.com/2011/08/23/rails-3-memcached-session-store/
For the purpose of your application, the first solution makes more sense though.

how to make rails-issued cookie work cross subdomain

I am having a situation when I am trying to make a RAILS application to be the backend core of my APIs. I am using 'devise' to authenticate the users, which does by putting a session cookie. This is so far perfect. and take in consideration that I am building this on "api.mydomain.com"
Now, I also have a javascript application running on "mydomain.com" which do AJAX calls to the API on the subdomain. I need to have the rails-issued cookie be valid and go on the headers when I make the API calls... It just doesn't.
I tried every single solution that I found on google, where it looks like putting this
Api::Application.config.session_store :cookie_store, key: '_api_session', :domain => ".mydomain.com"
into my config/initializers/session_store.rb was the default answer. this didn't work for me.
I also found some other recommendation on google that I shoudl put that in the environment file. that didn't work either for me.
Help will be appreciated.
Please note: I am running rails 3.2.11 should this matter.
Try using the :domain => :all option.
Source: Railsapps Tutorial on Subdomains (search for "Optional: Allow Sessions To Be Shared Across Subdomains")
I found that there is a better way to do that:
:domain => "*.domain.com"

Configuring Rails App to handle multiple subdomains and multiple cookies

I have a rails app which supports multiple domains and each domain may have multiple subdomains.
Users visiting mydomain1.com do not receive the same experience as mydomain2.com (although the base behaviour of the apps is the same)
Therefore, if a user is logged in to mydomain1.com, it shouldn't then be logged in to mydomain2.com
If a user is logged in to france.mydomain1.com, it should then be logged in to germany.mydomain1.com
Previously, I've handled this by setting the domain in the session store configs:
MyApp::Application.config.session_store :cookie_store, :key => '_MyApp_session', :domain => APP_CONFIG[:domain]
I'm trying to work out the best way to handle this with multiple domains?
I've tried hacking around ActionDispatch::Callback but the request is not available from within there.
Can anybody suggest a good way of supporting multiple cookies from within one app?
Ideally I'd like to create a fresh cookie for each subdomain.
You should do that:
class ActionDispatch::Session::MultiDomainStore < ActionDispatch::Session::CookieStore
def initialize(app, options = {})
super(app, options.merge!(:domain => compute_domain(app)))
end
def compute_domain(app)
...
end
end
MyApp::Application.config.session_store :multi_domain_store, :key => '_MyApp_session'
I.e. your domain should start with the dot.
It shouldn't be an issue as cookies are only valid per domain. You can have a _MyApp_session for example1.com and one for example2.com. The cookies are managed by the browser and only sent to the host if the domain matches.
Say you visit example1.com and log in and you will get a cookie with the value abcdef123. Then you log into example2.com and you will get another cookie with a random string uvwxyz890.
If you return to example1.com later, the browser will only send the cookies that are valid for this domain to your app. Your app won't have to manage anything and you don't have to hack anything.

How to secure a Rails app against Firesheep?

I have not been able to find an easy guide for securing a Ruby on Rails app against a Firesheep.
In case you don't know, Firesheep jacks session cookies if your app doesn't force SSL and set the secure flag in the cookie. I had to do some searching to find these two things, so I thought I'd post what I found here and see if there is anything else I'm missing.
Step 1 Force SSL
There are two ways to do this that I found. One is using the ssl_requirement plugin, but this is a pain because you have to specifically specify ssl_required :action1, :action2 in every controller.
The preferable way appears to be by using Rack Middleware, via this post: Force SSL using ssl_requirement in Rails 2 app. Works like a charm.
Step 2 Make cookies secure
For this I followed these directions, which tell you to put the following in your config/environment/production.rb file:
config.action_controller.session = {
:key => 'name_of_session_goes_here',
:secret => 'you need to fill in a fairly long secret here and obviously do not copy paste this one',
:expire_after => 14 * 24 * 3600, #I keep folks logged in for two weeks
:secure => true #The session will now not be sent or received on HTTP requests.
}
This was all pretty straight-forward on my Rails 2.x app. Did I miss anything? Is it different for Rails 3?
Looks pretty good to me. It's pretty similar in Rails 3, though by default the session config is stored in config/initializers/session_store.rb. I usually tweak mine to look something like...
MyApp::Application.config.session_store :cookie_store, :key => '_my_app_session',
:secure => Rails.env == 'production', # Only send cookie over SSL when in production mode
:httponly => true, # Don't allow Javascript to access the cookie (mitigates cookie-based XSS exploits)
:expire_after => 60.minutes
And the secret is held in config/initializers/secret_token.rb:
MyApp::Application.config.secret_token = 'secret secrets are no fun...'
If you have access to your Apache (or whatever) config, you can also force SSL usage at that level. Strikes me as a more appropriate place to do that, but I guess not everyone has that option.
Seeing as this SO post ranks pretty high in Google I thought I'd share the approach I used for securing an app.
If you want to ensure SSL and also ensure secure cookies then you could use a Rack middleware:
https://github.com/tobmatth/rack-ssl-enforcer
I evaluated lots of different options and configuration settings for doing this but the rack middleware felt like the best option with the least amount of config - very easy to deploy. It has some great config options to filter specific rules, hosts, paths etc.
I tested that it does indeed set secure cookies correctly and it does. The one thing I noted was it only did it when logging out and logging in again - but that was using Devise.

Resources