Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Log a user into their subdomain after registration with Rails and Devise

I'm using Devise for authentication in my Rails 3 app. The application uses PostgreSQL schemas and the Apartment gem to facilitate multi-tenancy.

Logging in and out of a specific subdomain is working great after an account is created. Users can only login on the subdomain for their specific account, which is great.

Here's where I'm running into issues...

A brand new user hits the sign up URL at:

http://foo.com/signup

By default, when they click submit, the new account is created, but the user is sent to:

http://foo.com/dashboard

Instead, I want them to go to:

http://myaccount.foo.com/dashboard

In order to achieve this, I overrode the after_sign_up_path_for method in my registrations_controller.rb file:

def after_sign_up_path_for(resource)
  root_url(:subdomain => resource.account.subdomain)
end

This works as intended--it loads the correct URL--but the user's session was created for the root domain (foo.com) instead of the subdomain, so the user is asked to sign in.

One suggestion I found is to change the config/initializers/session_store.rb to:

config.session_store :cookie_store, :key => '_domain_session', :domain => :all

But this allows anyone to login to an account on any subdomain, which obviously isn't cool.

Question: How can I ensure that the session created upon signup is valid for the subdomain that was created during the signup process

like image 347
Rob Sobers Avatar asked Dec 11 '13 04:12

Rob Sobers


2 Answers

You could use domain: :all option in your config.session_store and just have a before_action just as suggested by some in the comments.

So you'll still have the code in config/initializers/session_store.rb or in config/application.rb:

config.session_store :cookie_store, :key => '_domain_session', :domain => :all

Then in your application_controller add the following code:

#app/controllers/application_controller.rb
before_action :check_subdomain

def check_subdomain
  unless request.subdomain == current_user.account.subdomain
    redirect_to root_path, alert: "You are not authorized to access that subdomain."
  end
end
like image 182
Gjaldon Avatar answered Oct 01 '22 18:10

Gjaldon


Override the devise session controller.

Create a file with the exact path app/controllers/devise/sessions_controller.rb

Override the sessions_controller class in that controller. Paste in the code found at the link. https://github.com/plataformatec/devise/blob/master/app/controllers/devise/sessions_controller.rb

class Devise::SessionsController < DeviseController
 # copy-paste the devise session controller below.
 ...
end

Edit the create action to suit your needs.

def create
  self.resource = warden.authenticate!(auth_options)
  set_flash_message(:notice, :signed_in) if is_flashing_format?
  sign_in(resource_name, resource)
  yield resource if block_given?
  respond_with resource, :location => after_sign_in_path_for(resource)
end

I'm looking to see if I can figure out how exactly to make this work, but I know for sure that the result you want is attainable by overriding the devise session controller.

EDIT

If you are using cross-subdomain cookies, you could enforce the subdomain session with a before_filter. For example

before_action do 
    redirect_to root_path, alert: 'That subdomain does not belong to you' if request.subdomain != current_user.subdomain
end
like image 44
OneChillDude Avatar answered Oct 01 '22 18:10

OneChillDude