How can I get cookies specifically for a subdomain in Rails? - ruby-on-rails

I'm running into an issue with getting the right cookies for the current subdomain. I have two different instances of the same application, one running at the www subdomain and the other running at the test subdomain, but it seems like the test app is pulling in cookies from the www instead, even if there are explicit cookies for .test.domain.com (because it's different instances the same application, the cookie name is the same, but I am not looking to share sessions or cookies between the two instances).
Is there any way to specify what domain Rails should be looking for its cookies for? I have config.cookies.domain and config.action_controller.session[:domain] both set to "test.domain.com" (on the test app), but it doesn't seem to make any difference (and, as well, the cookies being set by the test domain are for some reason ending up with the domain .test.domain.com instead of test.domain.com and I'm not sure why, or if it's relevant).
Update: To make this more complex, I realized I do actually need the dot-prefaced cookie domains (ie. .test.domain.com and .domain.com), because in general, subdomains are supposed to share the main domain's cookies and session (it's only that the test subdomain is actually it's own application rather than being a subdomain of the main application). Obviously .domain.com cookies will apply to test.domain.com, but is there any way to make the explicitly test.domain.com ones take priority?

Related

How is a Cookie validated internally by ASP.NET MVC using CookieAuthenticationMiddleware

I'm trying to figure out how ASP.NET internally validates that a cookie will allow the user to access the application.
CookieAuthenticationMiddleware will set .AspNet.Cookies with an encrypted value. After .NET successfully decrypts the cookie on a request, what validation occurs then?
Developing locally with IISExpress if I have an application (#1) that sets an authentication Cookie after the user logs in, and I create a complete new application (#2) also running on localhost, that is also using CookieAuthentication. When I access #2 it will read the cookie from #1 and allows the user to access the application as well.
I'm trying to understand what the limits are for cookie authentication.
There's not really any "validation" per se. The cookie's encrypted key is used to reference the user that should be "logged in". It works in a very similar way to sessions, where the session cookie holds an encrypted session id that the server can use to look up and restore the session via.
The encryption/decryption is based on the machine key, which either may be explicitly set in the Web.config or generated automatically by ASP.NET. Only applications that share the same machine key may decrypt the cookie, which is why it's so important to protect your machine key.
Anyways, there's two factors involved here. First, cookies are domain bound: only the domain or subdomains of the domain the cookie is set on will be given the cookie. This is handled by the client (i.e. browser). Your two applications currently are able to both see the cookie because they're both running on localhost. However, if you were to deploy one at foo.com and the other at bar.com, then they would no longer be able to see each other's cookies.
Second, the machine key is typically by server (unless you explicitly set it in the Web.config per app). As a result, sites running on the same machine can usually decrypt each other's cookies (assuming they see them in the first place, which again, is based on their domain).
It's not clear whether you're happy or not about this arrangement. If your goal is to segregate the two sites running locally, such that they don't share cookies, you have a couple of options.
You can explicitly set a different machine key for each site in their respective Web.config files. They'll still receive any cookies set by the other site, but they'll no longer be able to decrypt them, which basically results in them being ignored.
You can customize the auth cookie name. Instead of using the default cookie name you can make one .Site1.Auth and the other .Site2.Auth. Then, even though either site will also receive the cookie for the other site, it will simply ignore it, because it's not the auth cookie for it.
If, however, you're intending to rely on this behavior in production as well (i.e. you actually want logging into one site to log you into the other as well), then you'll need to explicitly set the machine key to the same value in both site's Web.config files. Additionally, you'll need to deploy them on the same domain, or at least subdomains of that domain. In the case of subdomains, you'll need to set the cookie domain to be the wildcard domain .mydomain.com for both. Then, you could have one at foo.mydomain.com and another at bar.mydomain.com, and they'd both see the cookie because it was set on .mydomain.com. If you leave it the default, set on the actual domain of the site, then bar.mydomain.com could not see a cookie set by foo.mydomain.com because that cookie would be explicitly set only for foo.mydomain.com.
The primary validations are encryption and expiration. If apps share an encryption context (e.g. machine key) then they can share auth cookies (providing other client side sharing rules like domains and paths are satisfied). So yes it's expected that two apps using IIS Express localhost on the same machine would share cookies by default.
The expiration is also embedded in the encrypted value so the client can't tamper with it.

Rails: one app with 2 domains - share authentication

My site is at mydomain.com on Heroku with Devise authentication.
I bought a short url me.do that I also point to my same Heroku app.
When a user is signed in on mydomain.com I also need them to be signed in on me.do so when they go to me.do after signing in at mydomain.com they don't have to sign in again.
How can I share authentication sessions using Devise on both mydomain.com and me.do?
There is no easy way to share authentication across domains, since the authentication usually is bound to cookies (sessions) which only bind to one domain and are not accessible across domains.
The only way you can manage to have something like this is to make sure you set cookies on both domains on login. You can do this via a redirect loop:
login request arrives at domain1 (from login form for example)
you set the session cookie for domain1
then make a redirect to domain2 and set a session cookie there
and then redirect the user back to domain1 (proceeding where he originally was going)
to make sure this is not an endless loop you have to add some parameters in the redirects to know how to handle the situation.
BUT if at all possible to avoid it, i would advise you not to implement this. It is really bad practice to have not unique domains. even allowing domains with www and without can lead to quite a bit of confusion for the user and a lot of headaches to the developer - in your case it will be even worse.
The sessions are not as useful as they would normally be. Setting additional cookies or session values does NOT work anymore (unless you do the loop every time again). And until the user actually uses the second domain his session there might even have expired (depending how your authentication framework handles it).
Those are just some of the issues you might run into.

Delete Rails session cookies from Wordpress and vise versa

We are designing an application that will use Rails and Wordpress to interact with each other. We would like to have a universal logout where you could logout from either application and it would delete cookies from the other app. They will share the same host and toplevel domain. Is there a way to do this?
Access to a cookie is dependent on the domain of the server attempting to read the request -- and potentially the domain specified in the cookie. So assuming the domains match (e.g. www.example.com and www.example.com on both blog and Rails app) either should have access to a cookie set by the other.
If this is not the case (e.g. blog.example.com, www.example.com), you'll need to make sure when the cookie is set in either place, it's set for the entire domain (e.g. .example.com). But this doesn't help: while Rails can delete WP's cookie, and vice-versa, the method for creating (and using) them needs to be mutually understood.
So there's a twist here, since this is a session cookie; in this case, the cookie (which either app should have access to) is setting a value that is used and interpreted on the server side, where sessions are managed. WordPress and Rails both different methods and look for different cookies.
A solution (idea) would be to have one or the other subsystem catch incoming requests (most likely WP, and probably through some .htaccess RewriteRule, assuming you're using Apache) and create an intermediate cookie that the other could check that provides sufficient proof that the user has logged in correctly. WP's PHP for this is pretty good, and easily extended -- you just need to create some token that's a shared secret between the two apps (one of the values in wp-config.php such as LOGGED_IN_KEY might be a good option).
Maybe a solution would be to take the publicly available value from the WP cookie for username, and append the shared secret value and (in both systems) create an MD5 hash to store in a cookie. In this case, Rails' authentication would subordinate to WP's, so you would need to make sure Rails knew to delegate things like forgotten password, changed password, etc, to WP's mechanisms.
Obviously I am thinking aloud, but maybe this is a path to consider.
In any case, this is preferable to having both systems know how to trust the other's authentication.
Fiddling with cookie deletion appears to be dirty and error prone.
You might rather want to have a look at auth providers and the according plugins such as:
OAuth (WP - Rails; maybe make either side an OAuth provider)
CAS (WP - Rails)
LDAP (WP - Rails)
...
Maybe it's an option to switch from WP to one of Rail's CMS like:
Refinery CMS
Typo
...

What are the pros and cons of a default URL with www or without www?

We need to default URL to unique name. If it is www then with no prefix or vice versa. So decision to be made is either stick with www or with no prefix.
With no prefix cookie is set for all sub domains. What are other downsides for it? Or benefits?
Basically we need this for OpenID as OpenID will make users look different if they came from www or with no prefix.
As our site is new so we can go with either one. Also, how the domain name looks is not much of a concern.
You probably want to redirect (with a HTTP 301 - Permanent Redirect) one to the other anyway, since maintaining consistent urls is much easier that way. So whichever you decide, just make sure the actual authentication is done after the redirect, and users looking different won't be an issue.
That said, if you want www or not depends entirely on how other things in your appliction works. You mention that cookies for domain.com will be saved for all subdomains - is this something you want? Are you ever going to need to differentiate (for example, by allowing users to set up their own authentication systems for subdomains as a shared hosting service might do)?
If none of the differences you find between including and excluding www matter to your application, I'd go for not using www. The main reason for this is my picture of current trends on the internet - more and more applications (SO is an example of this) tend to leave the www out, both when linking to their own sites, and in marketing of different kinds.
However, the main point is make both work. You don't want your site to break because the user did(n't) type www at the beginning of the url.
By not using the www subdomain, you can suffer a performance hit when delivering static content, as noted here: http://developer.yahoo.com/performance/rules.html#cookie_free. As I understand it, if you use http://example.com/ and http://static.example.com for static content, any cookies you set on the main domain will be passed with requests to your static subdomain.
This can be avoided quite easily, by buying a distinct domain for static content. However, this can certainly be dealt with by using a www subdomain.
Then again, this is a very minor con, and really only comes into play when you're dealing with a high-demand site. (For example, Digg uses http://digg.com and http://*.diggstatic.com).
Ultimately, I would say that this is such a minor problem that it can probably be dealt with if performance starts to suffer. Don't optimize prematurely, and all that...
And, as #Tomas Lycken points out, make sure you account for www even if you don't use the subdomain.

Rails Cookie Setting Problems

I have a Rails app that sets a cookie and does a redirect to another server once the user is logged in. However, the cookie that the Rails app sets isn't seen by the server for some reason. I've tried setting http_only to false but I still can't even see the cookie unless the domain is the same as my Rails app. Here's the code I'm using to set the cookie:
cookies[:dev_appserver_login] =
{ :value => "#{email}:#{nick}:#{admin}:#{hsh}",
:domain => "webserver-to-redirect-to",
:expires => 30.days.from_now }
redirect_to session[:dest_url]
If I manually create a cookie with the Web Developer extension in Firefox it works fine, but not when Rails does it. Any ideas?
What are the redirecting and redirected-to servers? You can only set ‘domain’ to the current hostname or a parent domain, so if you're on a.example.com and you're redirecting to b.example.com, you have to set ‘domain’ to .example.com, not b.example.com as implied in the code snippet.
(And open domains like the .com TLD aren't themselves allowed as domain values, so if you want to pass a cookie from a.example.com to b.somewhereelse.com you will need a more complicated solution probably involving changing the code on somewhereelse.com.)
I still can't even see the cookie unless the domain is the same as my Rails app.
That's how cookies are supposed to work. If you're accessing it directly by IP, then as far as the web browser is concerned, your 'domain' is just your IP, so the same rules apply.
You can get around this in development mode by editing your /etc/hosts file and creating host names for your apps
127.0.0.1 app1.localdev.com, app2.localdev.com
Then, when the cookie is created set the domain to '.localdev.com' (note the preceeding period') which will allow any app at any subdomain of localdev.com to read it.
Another broader solution (which is better for production deploys, but more work to set up) is to set up a path proxy for the sub-app so requests to appdomain.com go to app1 and requests to appdomain.com/other-app/ are proxied to the other app. This lets them share the root domain and easily share cookies.

Resources