Configuring Rails App to handle multiple subdomains and multiple cookies - ruby-on-rails

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.

Related

How to store the flash in a different cookie to the Rails session?

We have the Rails session cookie set to be only visible on the subdomain it is issued (i.e. setting domain: nil in the session store configuration). This means there are separate user sessions per subdomain, which is what we want.
However, we would still like the flash messages to be visible across subdomains. So if they log out on foo.oursite.com and are redirected to www.oursite.com, they should see the "logged out successfully" message from the flash, despite it being different subdomains.
So my question is: can we configure the Rails flash system to use a separate cookie to the session store, so we can set domain: :all for that cookie and have the flash be visible across subdomains?
(We are on Rails 5.0)
You could do something like e
Yourapp::Application.config.session_store :cookie_store, key: '_yourapp_session', :domain => :all
But this would mean all your cookies are accessible across sub-domains and would share the logged in session cookie.
You would maybe want to look into storing alerts in the database and retrieve them as needed.

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
}

Delete Session Cookies Across Multiple Subdomains in Rails 3

I'm building a rails app that works similar to Wufoo. When you sign up you get a subdomain, and you can log in on the home page. The app is working, so that when you log in, you get redirected to your subdomain. The problem is that I can't delete the session on both domains. If you log out at (username.myapp.com), it stays logged in at (myapp.com) and vice versa.
Right now I'm using session[:user_id] = nil to delete the session. Is there a way to delete all the sessions across all domains.
In addition, I appended :domain => :all to my session_store.rb file so I could stay logged in across multiple subdomains.
The key is really how you set your session cookies, because you can't delete a subdomain cookie (username.myapp.com) from a top-level domain (myapp.com). To solve this you'll want all your shared session cookies to be set under the myapp.com domain. To do this, setup your sessions in the following way:
Rails.application.config.session_store :cookie_store, :domain => 'myapp.com'
That way, when you destroy your session (session[:id] = nil) you'll be removing the shared cookie. I believe you will also have to delete the session using session[:id] instead of session[:user_id].

How maintain users authentications\sessions through multiple application?

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.

How to handle session domains in a cname forward supporting rails saas software

I have read
How to give cname forward support to saas software
Rails - Multiple top level domains and a single session/cookie
But I am unable to get a solution for the following setup:
A SaaS Webapp in Rails is running under example.com
All users have a sumbdomain e.g. user1.example.com
Users can create a cname forwarding eg. exampleapp.user1.com -> user1.example.com
It is all working until a user tries to log in via exampleapp.user1.com. The SaaS app fails to set the session domain right, because it is configured static on app startup.
config.action_controller.session = {
:session_key => '_example_session',
:domain => ".example.com",
:secret => 'abc'
}
The Request fails with a ActionController::InvalidAuthenticityToken. And that is correct, because the domain changed from .example.com to exampleapp.user1.com.
How do I change the domain config during runtime? I know that the "incoming" domain exampleapp.user1.com belongs to user1, so I want to do something like that in the controller:
session :domain => 'exampleapp.user1.com'
Or can I always set the session domain on the current request domain?
I know that it's possible somehow, because some apps provide that functionality.
Thanks in advance!
:domain => :all on the cookie config may work.
For CNAME'd domains, it will be set to .theirdomain.com
For your custom subdomain, it will go to .yourdomain.com, which may or may not be good
Just don't set the domain, since apparently you don't need to share a session cookie across example.com and user1.example.com. By not specifying a domain, the default cookie behavior is just to be set for the current request domain.

Resources