how should I go about making all Devise paths use https? - ssl

Related: Rails 3 SSL routing redirects from https to http (unfortunately didn't work).
Duplicate, but the answer didn't work for me: setting up ssl on devise
I have a web app that's been working fine for a while now but I need to add SSL to the login/edit acct paths. I'm using Devise for authentication. I found an entry in the devise wiki that made the process seem pretty simple, but damn if I can get it to work. The simple part was this:
#in config/environments/production.rb
config.to_prepare { Devise::SessionsController.force_ssl }
config.to_prepare { Devise::RegistrationsController.force_ssl }
And then there's about 25 lines of code in this gist: https://gist.github.com/1040964
I got that to work well enough, but when ever I sign out I get a 301 from the sessions DELETE action that sends me to a GET.
Started DELETE "/users/sign_out" for 98.246.164.160 at 2012-03-02 01:45:42 +0000
[02 Mar 01:45 10886 INFO] Processing by Devise::SessionsController#destroy as HTML
[02 Mar 01:45 10886 INFO] Parameters: {"authenticity_token"=>"fI4VZ4V0Go2Civo3sJz8Dv5/Wtaa90ynaYr+xxx="}
[02 Mar 01:45 10886 DEBUG] Parameters: {"_method"=>"delete", "authenticity_token"=>"fI4VZ4V0Go2Civo3sJz8Dv5/Wtaa90ynaYr+xxxx=", "action"=>"destroy", "controller"=>"devise/sessions"}
[02 Mar 01:45 10886 INFO] Redirected to https://ec2-xx-xx-106-255.us-west-2.compute.amazonaws.com/users/sign_out
[02 Mar 01:45 10886 INFO] Completed 301 Moved Permanently in 3ms
Started GET "/users/sign_out" for xx.xx.164.160 at 2012-03-02 01:45:42 +0000
[02 Mar 01:45 10886 FATAL]
ActionController::RoutingError (No route matches [GET] "/users/sign_out"):
So I think I need to start over from scratch. What's the simplest way to make any Devise path use https, but the rest of the paths in my app use http? I tried this (from the SO post at the top):
#devise routes
scope :protocol => 'https://', :constraints => { :protocol => 'https://' } do
devise_for :users, :controllers => { :registrations => :registrations }
devise_for :admins
end
But no go. I need a better suggestion.

No answers yet, so here's what I concluded:
Once you access a site via https, don't access it via http until the user signs out (firesheep attack). There's a lot of stuff on Devise in the article linked above that discusses only having https on the sign in / out page. Bad idea.
All you really need is this:
#in config/environments/production.rb
config.to_prepare { Devise::SessionsController.force_ssl }
config.to_prepare { Devise::RegistrationsController.force_ssl }
I had a ton of issues surrounding 'after_sign_in_path' from Devise. It turns out that after_sign_out_path_for is expecting a path to be returned -- it's not an event, it is asking where the user should be directed. So I returned root_path :protocol => 'http://' and that took care of it.

Try making your whole app use HTTPS by adding:
#in config/environments/production.rb
config.force_ssl = true
I had quite the same problem. Sometimes I sign out fine sometimes I got 301 from DELETE action and redirect to GET. For me this was the problem.

Make sure you use https in all your Devise links (this avoids the force_ssl redirect).
In your routes.rb (only applied in production environment):
scope defaults: (Rails.env.production? ? { protocol: 'https' } : {}) do
devise_for :users
end
Now in your application use:
destroy_user_session_url # use _url instead of _path so the protocol is added!
Now your logout / sign out link (and other devise links) will point directly to https. The force_ssl rewrite from HTTP DELETE to HTTPS GET is avoided. It all works :)

Related

Select SSL Routes serving up rails 4 static pages via highvoltage gem

I have several static erb pages being served up in a ruby rails 4 site via the high voltage gem:
get '/about' => 'high_voltage/pages#show', id: 'about'
get '/contact' => 'high_voltage/pages#show', id: 'contact', :protocol => "https"
get '/privacy' => 'high_voltage/pages#show', id: 'privacy'
This all works well and good, except that the /contact route doesn't redirect or force SSL on, it is happy with whatever protocol is used.
I host the site on engine yard, attempting to put :force_ssl only or variants in the route line resulted in failed deployments - high voltage uses a slightly different set of arguments than normal routes so I suspect there is a conflict somewhere.
Anyone use highvoltage and SSL with rails 4 for select static pages (not the whole site)? Example routes line please.
You can achieve this by overriding the HighVoltage#PagesController see the override section of the documentation.
It might look something like this:
class PagesController < ApplicationController
include HighVoltage::StaticPage
before_filter :ensure_secure_page
private
def ensure_secure_page
if params[:id] == 'contact'
# check to make sure SSL is being use. Redirect to secure page if not.
end
end
end
Next disable the routes that HighVoltage provides:
# config/initializers/high_voltage.rb
HighVoltage.routes = false
Then in your application's routes file you'll need to set up a new route:
# config/routes.rb
get "/pages/*id" => 'pages#show', as: :page, format: false

Secure session cookies for rails application

I have the following configuration in my session_store.rb
Fuel::Application.config.session_store :cookie_store,
:key => "_secure_session",
:secure => !(Rails.env.development? || Rails.env.test?),
:domain => :all
In application_controller.rb
def default_url_options
return { :only_path => false, :port => 443, :protocol => 'https' }
end
I am using devise and my rails3 server is running behind HAProxy. HAProxy terminates the HTTPS traffic and passes HTTP requests to Rails. My problem is when i turn on :secure => true in session_store.rb, the user is redirected back to the sign in page with the message "Unauthorized". I have tried debugging it a lot, not sure how to get it working.
Its a situation where HAProxy is the reverse proxy terminating all the secure traffic and passing non-secure traffic to rails. When rails sets the cookie to secure, somehow it itself is not able to access it.
For your normal session cookie, your doing this correctly. You should see the '_secure_session' cookie properly set as secure in your browser. For the Devise "remember me" cookie you'll need to set that in the devise config. In config/initializers/devise.rb you'll find a line somewhere around line 133 that looks like
# Options to be passed to the created cookie. For instance, you can set
# :secure => true in order to force SSL only cookies.
# config.cookie_options = {}
I changed that to:
config.rememberable_options = {:secure => Rails.env.production?}
If Set-cookie is not being sent to the browser on initial authentication, then it sounds like a devise problem.
If Set-cookie is going to the browser, but not being sent back on the next https:// request, then it's probably a mismatch on :secure => setting.
If the cookie is sent by the browser, but not passed along by HAProxy, then it's a HAProxy configuration problem.
If the cookie is in the ruby environment, and being ignored due to policy, then it's a problem somewhere in Ruby code - at a guess, around secure/not-secure cookie-matching.

Subdomain constraint (Rails 3) makes local server (thin) SO SLOW

I recently added a subdomain constraint to my Rails routes file
constraints(:subdomain => 'new') do
devise_for :customers do
get "/customers/sign_up" => "registrations#new"
post "/customers" => "registrations#create"
put "/customers/:id" => "registrations#update"
end
match '/' => 'roxy#index'
namespace :roxy, :path => '/' do
resources :customers
resources :surveys
end
end
In order to test the subdomain routing constraint locally, I added this line to my hosts file.
127.0.0.1 new.localhost.local
Now, I test my app in my browser at the URL new.localhost.local:3000. It takes about 10 - 15 seconds to load every page, which is unreasonably slow. If I remove the subdomain constraint and just go to 127.0.0.1:3000, everything is zippy and fast again.
What am I doing wrong? I'm new to Rails, so please tell me if there is a better way to do subdomain routing in rails, or if there is a setting I need to configure.
Figured it out. It's nothing to do with Rails or subdomains or thin. Turns out, unlike other unixy-things, OS X reserves the .local TLD for mDNS functionality. For every page, the DNS resolution was timing out before loading my app. So I just changed my /etc/hosts file to
127.0.0.1 new.localhost.dev
and everything's working great now.
Read more: http://www.justincarmony.com/blog/2011/07/27/mac-os-x-lion-etc-hosts-bugs-and-dns-resolution/

switched to ssl and devise tokens are invalid

We just switched our rails 3 app over to SSL, and later noticed that password recovery tokens aren't working in production any longer. It says "invalid token" when a user tries to reset their password using the emailed link.
I'm using rails 3.0.0, devise 1.3.4, and our user model has:
devise :database_authenticatable, :invitable, :registerable,
:recoverable, :rememberable, :trackable, :validatable
I'm not using anything like ssl_requirement, because we just did ssl universally across the app. I expired old tokens to make sure it wasn't somehow not expiring old tokens or something. I'm baffled.
This was a problem with our nginx config, and entirely unrelated to Devise. But in case anyone else ever finds themselves in a similar position, here's what went down. We set up nginx to redirect the plain http urls to https.. Specifically we had a double rewrite when someone went from domain.com to www.domain.com to https://www.domain.com, and the reset_code was getting added to the end a second time so that reset_code was coming through to the app as ?reset_code=12345?reset_code=12345.
So we changed our nginx config so:
# rewrite ^ https://$server_name$request_uri permanent;
rewrite ^(.*) https://$host$1 permanent;
and then just an optimization
rewrite ^(.*)$ https://www.domain.com$1 permanent;
and all better now.
The answer provided above is correct. But it is a temporary solution and it works only for devise. However the problem arises when you manually send a confirmation token via email.
You can fix this permanently.Go to environment/production.
and change this line
config.action_mailer.default_url_options = { :host => 'domainname', :protocol => "http"}
to
config.action_mailer.default_url_options = { :host => 'domainname', :protocol => "https"}

Phusion Passenger - route exists but is not matched (gives 404 instead)

I'm running a rails 3 app at the root level in a phusion passenger environment (CentOS, apache) and having difficulty getting passenger to find some routes, although rake routes shows the routes correctly. Everything works fine in development (i.e. using rails server instead of phusion passenger in apache).
I have an admin section to my app with a login page. The main part of the app works, but everything under the admin section is inaccessible because I get a 404 instead of the login page (when I disable login I can access the admin pages). My apache config is
<VirtualHost *:80>
ServerName foo.bar.com
DocumentRoot /var/www/apps/myapp/current/public
<Directory /var/www/apps/myapp/current/public>
Allow from all
Options -MultiViews
</Directory>
</VirtualHost>
My login process is implemented as a before_filter in an admin controller:
class Admin::AdminController < ApplicationController
# login disabled for testing
before_filter :require_login
def require_login
#current_user ||= User.find_by_id(session[:user_id])
redirect_to admin_login_path unless #current_user
end
end
My routes file has
Mpf::Application.routes.draw do
secure_protocol = "https://"
...
namespace "admin" do
...
match "login" => "user_sessions#new", :as => :login, :constraints => { :protocol => secure_protocol }
...
end
...
end
and when I run rake routes I get
admin_login /admin/login(.:format) {:protocol=>"http://", :action=>"new", :controller=>"admin/user_sessions"}
BUT when I try to access http://foo.bar.com/admin I get a 404 and the log shows
Started GET "/admin/login" for iii.iii.iii.iii at 2011-07-13 07:20:41 -0400
ActionController::RoutingError (No route matches "/admin/login"):
As far as I can tell it should be working... except for the fact that it's not. Any help would be greatly appreciated!
Have you tried accessing with https://? It looks like you provided constraints to prevent access from http:// and the link you posted references http://.