Handling mix of HTTP and HTTPS links on a page - ruby-on-rails

My setup: Rails 3.0.9, Ruby 1.9.2
My app requires that only a certain part of my site be SSL protected and the rest not. In case anyone thinks this isn't normal behavior, check out Amazon. When merely browsing for products, it's in HTTP mode, during checkout, it switches to HTTPS. Even in the middle of a secure checkout transaction, there are several other links on the same page that are HTTP only.
I looked at ssl_requirement gem and decided not to use it because it isn't a complete solution for my needs. I ended up setting up specific SSL routes like
resources :projects do
resources :tasks, :constraints => { :protocol => "https" }
end
In my view code, for HTTP specific links
<%= link_to 'Projects', project_url(#project, :protocol => "http") %>
and to handle HTTPS specific link
<%= link_to 'Task', new_project_task_url(#project, :protocol => "https") %>
I understand this isn't the cleanest way but it's what I have decided to do. The problem with this setup is how to properly set both HTTP and HTTPS links on every page. There is a proposed solution here but it requires wholesale changes _path to _url and I prefer to avoid that if at all possible. The solutions involves adding this method in
application_helper.rb
module ApplicationHelper
def url_for(options = nil)
if Hash === options
options[:protocol] ||= 'http'
end
super(options)
end
end
So my question is it possible to change this method or another one to change _path calls to explicit urls so I can use the above method to set the proper protocol.

you could try this, although I'm not 100% sure it works:
Use the proposed changes from the stackoverflow answer
Add this to application_controll.rb:
class ApplicationController < ActionController::Base
def url_options
{ :host => request.host }.merge(super)
end
end
According to the Docs it should add the full url even if you use _path:
:only_path - If true, returns the relative URL (omitting the protocol,
host name, and port) (true by default unless :host is specified).

My app requires that only a certain part of my site be SSL protected and the rest not.
That's your faulty assumption. The secure premise is that if some of your app requires SSL, then all of your app requires SSL. The correct assumption then is that your entire app requires SSL.
If your app requires SSL, then you should use something simple like rack-ssl which sets the HSTS header and enforces the secure flag on cookies in all responses.

Related

Dynamically preset a url for development and production environments

I'm creating a password reset functionality for my site in rails and in my mailer password_reset.text.erb file I'm currently sending
http://localhost:3000/password_resets/<%=#user.password_reset_token%>/edit/
in my development environment. This will hit my controller for password reset and redirect the user to edit the password if the token matches with the saved model.
However, I'd like to configure this dynamically so when I deploy to heroku it will know to change that to mywebsite.com/password_resets/...
How would I do this?
EDIT:
def password_reset(user)
#user = user
mail(to: user.email, subject: "Bitelist Password Reset")
end
Typically I configure the host information for the mailer in an appropriate config/environment file.
config.action_mailer.default_url_options = { :host => "example.com" }
You can take a look at the "Generating URLs" section of this page: http://rails.rubyonrails.org/classes/ActionMailer/Base.html
With that configuration set typical routing structures seem to work quite nicely. I am not 100% positive what routes will be available in your situation so you may still need to construct the full URL somewhat manually to include the reset token component.
To generate the actual URLs you can potentially use named routes if your routes are set up in a way that you have a named route that takes a user token. i.e.
<%= edit_password_resets_url(#user.password_reset_token) %>
If you do not have the token integrated into an existing route you may need to manually build the URL:
<%= "#{url_for(:controller => 'password_resets', :action => 'whatever_action_this_is')}/#{#user.password_reset_token}/edit/" %>
or even build it completely manually using default_url_options[:host] and then add the rest that you have above.
If need be you could also set the host at request time although that may be overkill (and will not be thread safe).
def set_mailer_host
ActionMailer::Base.default_url_options[:host] = request.host_with_port
end

Rails URL generator switch http / https

Is there a way to put in links to external resources that automatically adds the protocol based on the current protocol?
For example I want to show images from Facebook's Graph API. I was hoping I could do something like:
image_tag url_for("/1234567/picture", :host => "graph.facebook.com")
So that the url_for just bases the protocol on the current request's protocol.
I know this works but I'm hoping there's a better way:
image_tag("#{request.protocol}://graph.facebook.com/1234567/picture")
You can add the protocol option to url_for.
image_tag url_for("/1234567/picture", :host => 'graph.facebook.com', :protocol => request.protocol)
or maybe a better way would be to create a helper (if you do this a lot) called url_for_same_protocol (or whatever you want):
class ApplicationHelper
def url_for_same_protocol(url, options)
options[:protocol] ||= request.protocol
url_for url, options
end
end
.. and then just replace your url_for call with url_for_same_protocol.

Getting Rails URL helpers to automatically output https urls

I am developing a site that mixes http and https a lot - whats the best/easiest way to make the links use the right protocol for the route - can it be specified in the routes file?
Say I have the following route in Rails 3.
match "/test" => "test#index", :as => :test, :constraints => { :protocol => 'https' }
If I'm on a http page, and I use test_url(), it'll output http://domain.com/test. I want https://domain.com/test instead.
I know I can use test_url(:secure => true), but that's duplicating logic.
I know I could have http://domain.com/test to https://domain.com/test, but that's an extra redirect, plus it fails on form posts.
Ideas?
Use test_url(:protocol => 'https') for https urls.
Haven't tried but add this in your ApplicationController:
def default_url_options(options={})
{ :secure => true }
end
def default_url_options(options={})
{ :protocol => "https" }
end
For Rails 3.2 I used a combination of #apneadiving's answer. Adding the below code to my ApplicationController
def default_url_options(options={})
options.merge{ :protocol => "https" }
end
It looks like this will be solved in Rails 4! https://github.com/rails/rails/commit/9b4514c3b8ecfbc40a44dbd4c2ebd4ce67f4a459
Rails 3 SSL routing redirects from https to http answers this question pretty well. In short, there's not a great way to do it. I submitted the following Rails bug: https://github.com/rails/rails/issues/3571
To generate https url, add an option called protocol with value https
test_url(protocol: 'https')
You can use a plugin called ss_requirement, it will provide you with methods like
ssl_required
ssl_allowed
You can simply add this in your controller to enable ot disable https on any action
ssl_allowed :login, :update_profile
https://github.com/rails/ssl_requirement

Rails 3 passing parameters between non-secure and secure pages

This seems like a pretty straight-forward question, but Google is failing me.
My currently all-SSL site needs to be only partially secure (it's not search engine friendly otherwise). But while I want my home page to be unsecure, there's a form on that page that does go to a secure page. As things stand, any form parameters going to a secure site are lost, causing the usual mayhem.
What is the best practice for this situation? In terms of my setup, I'm using rack-ssl-enforcer gem for Rails 3 (works beauty, btw). But these secure and non-secure pages need to co-exist somehow.
Thanks!
Aaron
not sure i get the point, but why don't you use the :except or :only option:
config.middleware.use Rack::SslEnforcer, :only => /^\/admin\//
config.middleware.use Rack::SslEnforcer, :except => /^\/home\//
Then, use the :protocol option for your form, e.g.
# PagesController#home
%h1 Home
= render 'comments/form'
# CommentsController#_form
= form_for #comment, :url => comments_path, :protocol => https
...
That should do the trick...

Modifying rails route helper

I'd like to modify the behavior of the rails route helper *_url for a single route/page.
Here's what I'm try to do:
User visits:
http://test1.myapp.com/account
All the *_url routing helpers resolve to http://test1.myapp.com/ as normal.
But, then if the user goes to https://myapp.heroku.com/account/billing?id=test1
I'd like all the *_url routing helpers on that page to resolve to: http://test1.myapp.com/
instead of http://myapp.heroku.com/
So, is it possible to change the domain bit for all the *_url helper calls for a specific page?
For those interested, I'm trying to use heroku's piggyback ssl method for my app for just a secured billing page.
You can actually just modify the links that point to the billing area:
<%= link_to "Billing", my_helper_url(test1, :host => "myapp.heroku.com", :protocol => "https") %>

Resources