Ruby on Rails allowing sessions between ports locally - ruby-on-rails

Basically I am developing an API in rails with RocketPants and Devise and I'm creating a client with AngularJS. since they are in folders maintained by seperate people I run the rails api on localhost:3000 and the client on localhost:8000 and in the live environment they will be on subdomains of the same top level domain. api.example.com app.example.com.
I have allowed for cross domain requests using Rack Cors and this seems to work fine, I can query for things and log in by sending my credentials to the API (I have also checked if this works by returning the logged in user's id).
However the client does not seem to hang on to the session, after I log in and get back confirmation that I logged in successfully and I make another request it says the current_user is Nil.
I have allowed for subdomains in rails I think by using the following in session_store.rb
AppName::Application.config.session_store :cookie_store, key: '_app-name_session', domain: :all
I cannot test this however.
Is there a good way to share sessions between ports locally? Or is there a good way to emulate subdomains for local testing between 2 projects (1 rails, 1 standalone)?

Have you considered using Pow to serve your apps in development?
You could then run them on the subdomains, just like you do in production.

Related

One domain, two rails apps on Heroku

I am building a multi-tenant Rails 5 app (will be hosted at heroku) at the moment (using apartment gem) which will have clients scoped by subdomain, e.g. client1.example.com, client2.example.com, client3.example.com. All seems pretty straight forward, but I would love to have a second Rails app for the rest of the site e.g. example.com/pricing, example.com/faq. What would be the best solution to achieve this design:
example.com/pricing - served by Rails App 1
example.com/faq - served by Rails App 1
example.com/{sign_in | sign_up} - served by Rails App 2
clientX.example.com/{projects | profiles | other stuff} - served by Rails App 2
I have a suspicion that sign in/up bit might not be possible due to same URL structure, so I might need to have an extra logic built it for it maybe under app.example.com/sign_up or even under Rails App 1. Any suggestion how to build this in a better way would be appreciated!
A little concerned this will be closed with "overly broad", but a simple solution here is to do heroku domains:add www.example.com and heroku domains:add example.com to Rails app 1. Then heroku domains:add *.example.com on Rails app 2 and to have two entirely separate apps on Heroku.
Don't think you can mount two apps under the root directory. You might be able to achieve this if you're willing to namespace your Devise paths under a subdirectory, eg. /session/sign_up and /session/sign_in
This will require an extra app (App 3) which just runs Devise loaded and deployed under the /sessions subdirectory. You'll need to configure the relative url root for this app.
This will make authentication more complex as your session authentication cookie will be under your root domain instead of your individual subdomains. You'll probably need to use the domain: :all or domain: .<domain>.com option in initializers/session_store.rb to share the cookie with subdomains. secret_key_base also needs to be identical across all your apps.
You'll also need to play with Devise's session creation to redirect to the correct subdomain for the user upon signing in. Fun fact to think about - what if the user has accounts on multiple subdomains with the same email? Devise/Warden scopes might offer a way to handle that.
On the Heroku side:
Heroku can only route requests for one domain to one app (App 1). The Rack reverse proxy posted above will allow you to route authentication requests to App 3. For individual subdomain requests to be routed to App 2, you'll need to add each subdomain to App 2 as a separate custom domain.

Rails CSRF validation not working with proxy server in production

I have a simple feedback form on my Rails 5 app, which is failing CSRF validation on POSTs - but only in production. More specifically, the production server is foo.example.com, but the service is accessed by a proxy server proxy.example.com. There's an Nginx server running on the proxy that routes requests to the appropriate application server.
If I browse directly to http://foo.example.com, and submit the form, everything is fine. But submitting the same form when viewed as https://proxy.example.com, I get the CSRF failure. There are two key differences between the two access routes: the request rewriting by the proxy, and http vs. https. I'm not sure which is the relevant factor.
One theory was that the domain used by the session store was not coming out correctly, but I tried various variants of passing domain: to Rails.application.config.session_store, but none of them made any differences. After that, I've rather run out of hypotheses as to where to look.

SSL Requests on staging environments fail

Our mobile app recently stopped authenticating properly with our server on our staging and staging2 environments. Fortunately production is fine.
We're using force_ssl in our API's Session and Registration controllers. It was working fine before; not really sure what changed.
What seems to be happening is that our app submits a POST request to either create a new session or user. This request is over SSL, but we get a 301 Moved Permanently with a location identical to the initial request. I believe this redirect is performed via GET and since no routes match a GET to that URL, we then get a 404 Not Found.
I can't figure out why this changed recently and why it's not affecting production.
Turns out it was something having to do with Engine Yard, and an upgrade of our environment solved the problem.

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.

Rails, Devise, and multiple domains

Let's say I have an application that's going to be accessed from completely different domains that all point at the same server*:
example.com, example.net, foobar.com, ...
I have a Devise based authentication system that's worked fine before. However, the goal is now to add HTTPS to the sign in system. The problem is, as it turns out, there is no way to host more than one HTTPS website on the same IP address**. To resolve this problem, I set up the login pages to always POST to https://secure.example.com. As far as I can tell, this is working fine. Devise seems to have no qualm with it. However, the tricky part is that the user now needs to be redirected to foobar.com, which also needs to understand that the user is logged in. I pass the site to return to in a hidden parameter in the login form, and the redirection works fine. I still have no way to inform foobar.com that the user is now logged in.
I've managed to set it up so that, upon being returned to foobar.com, it copies the user's session cookie for secure.example.com into a new cookie for foobar.com. This part is working fine. However, in the Rails console, the web requests for secure.example.com and foobar.com - with the same cookie sent for each - produce two completely different sessions and therefore, it's no wonder Devise acts like the user was never logged in to foobar.com
Does anyone know why this wouldn't work - why two identical web requests (only the domain of the request URI was different - I tried it in Firebug, too) would produce two completely different sessions in a Rails 3 app with different, yet consistent, session ids? More to the point, does anyone know how to MAKE this work?
* assume, for the purposes of this exercise, that this is unavoidable and the sites cannot be hosted all under different subdomains, and that the number of domains required is too great to get a separate IP address for each.
** unless they're subdomains and you have an *.example.com cert, but that's beside the point.
If you're already using Devise, I suggest you try using token authenticatable. You can generate a token for the user in question, redirect them with the token to sign in, and then quickly expire the token after they have signed in.
You could also try rolling your own OAuth provider with doorkeeper.

Resources