Project

General

Profile

0001-Require-SSL-for-hosts-controller.patch

Frank Sweetser, 12/10/2009 06:23 PM

View differences:

app/controllers/application_controller.rb
3 3

  
4 4
class ApplicationController < ActionController::Base
5 5
  protect_from_forgery # See ActionController::RequestForgeryProtection for details
6
  include SslRequirement
6 7

  
7 8
  filter_parameter_logging :root_pass
8 9

  
app/controllers/hosts_controller.rb
2 2
  before_filter :require_login, :except => [ :query, :externalNodes ]
3 3
  before_filter :find_hosts, :only => :query
4 4

  
5
  def ssl_required?
6
    true
7
  end
8

  
5 9
  helper :hosts
6 10

  
7 11
  active_scaffold :host do |config|
vendor/plugins/ssl_requirement/README
1
SSL Requirement
2
===============
3

  
4
SSL requirement adds a declarative way of specifying that certain actions
5
should only be allowed to run under SSL, and if they're accessed without it,
6
they should be redirected.
7

  
8
Example:
9

  
10
  class ApplicationController < ActiveRecord::Base
11
    include SslRequirement
12
  end
13

  
14
  class AccountController < ApplicationController
15
    ssl_required :signup, :payment
16
    ssl_allowed :index
17
    
18
    def signup
19
      # Non-SSL access will be redirected to SSL
20
    end
21
    
22
    def payment
23
      # Non-SSL access will be redirected to SSL
24
    end
25

  
26
    def index
27
      # This action will work either with or without SSL
28
    end
29

  
30
    def other
31
      # SSL access will be redirected to non-SSL
32
    end
33
  end
34
  
35
You can overwrite the protected method ssl_required? to rely on other things
36
than just the declarative specification. Say, only premium accounts get SSL.
37

  
38
P.S.: Beware when you include the SslRequirement module. At the time of
39
inclusion, it'll add the before_filter that validates the declarations. Some
40
times you'll want to run other before_filters before that. They should then be
41
declared ahead of including this module.
42

  
43
Copyright (c) 2005 David Heinemeier Hansson, released under the MIT license
vendor/plugins/ssl_requirement/lib/ssl_requirement.rb
1
# Copyright (c) 2005 David Heinemeier Hansson
2
#
3
# Permission is hereby granted, free of charge, to any person obtaining
4
# a copy of this software and associated documentation files (the
5
# "Software"), to deal in the Software without restriction, including
6
# without limitation the rights to use, copy, modify, merge, publish,
7
# distribute, sublicense, and/or sell copies of the Software, and to
8
# permit persons to whom the Software is furnished to do so, subject to
9
# the following conditions:
10
#
11
# The above copyright notice and this permission notice shall be
12
# included in all copies or substantial portions of the Software.
13
#
14
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21
module SslRequirement
22
  def self.included(controller)
23
    controller.extend(ClassMethods)
24
    controller.before_filter(:ensure_proper_protocol)
25
  end
26

  
27
  module ClassMethods
28
    # Specifies that the named actions requires an SSL connection to be performed (which is enforced by ensure_proper_protocol).
29
    def ssl_required(*actions)
30
      write_inheritable_array(:ssl_required_actions, actions)
31
    end
32

  
33
    def ssl_allowed(*actions)
34
      write_inheritable_array(:ssl_allowed_actions, actions)
35
    end
36
  end
37
  
38
  protected
39
    # Returns true if the current action is supposed to run as SSL
40
    def ssl_required?
41
      (self.class.read_inheritable_attribute(:ssl_required_actions) || []).include?(action_name.to_sym)
42
    end
43
    
44
    def ssl_allowed?
45
      (self.class.read_inheritable_attribute(:ssl_allowed_actions) || []).include?(action_name.to_sym)
46
    end
47

  
48
  private
49
    def ensure_proper_protocol
50
      return true if ssl_allowed?
51

  
52
      if ssl_required? && !request.ssl?
53
        redirect_to "https://" + request.host + request.request_uri
54
        flash.keep
55
        return false
56
      elsif request.ssl? && !ssl_required?
57
        redirect_to "http://" + request.host + request.request_uri
58
        flash.keep
59
        return false
60
      end
61
    end
62
end
vendor/plugins/ssl_requirement/test/ssl_requirement_test.rb
1
begin
2
  require 'action_controller'
3
rescue LoadError
4
  if ENV['ACTIONCONTROLLER_PATH'].nil?
5
    abort <<MSG
6
Please set the ACTIONCONTROLLER_PATH environment variable to the directory
7
containing the action_controller.rb file.
8
MSG
9
  else
10
    $LOAD_PATH.unshift << ENV['ACTIONCONTROLLER_PATH']
11
    begin
12
      require 'action_controller'
13
    rescue LoadError
14
      abort "ActionController could not be found."
15
    end
16
  end
17
end
18

  
19
require 'action_controller/test_process'
20
require 'test/unit'
21
require "#{File.dirname(__FILE__)}/../lib/ssl_requirement"
22

  
23
ActionController::Base.logger = nil
24
ActionController::Routing::Routes.reload rescue nil
25

  
26
class SslRequirementController < ActionController::Base
27
  include SslRequirement
28
  
29
  ssl_required :a, :b
30
  ssl_allowed :c
31
  
32
  def a
33
    render :nothing => true
34
  end
35
  
36
  def b
37
    render :nothing => true
38
  end
39
  
40
  def c
41
    render :nothing => true
42
  end
43
  
44
  def d
45
    render :nothing => true
46
  end
47
  
48
  def set_flash
49
    flash[:foo] = "bar"
50
  end
51
end
52

  
53
class SslRequirementTest < Test::Unit::TestCase
54
  def setup
55
    @controller = SslRequirementController.new
56
    @request    = ActionController::TestRequest.new
57
    @response   = ActionController::TestResponse.new
58
  end
59
  
60
  def test_redirect_to_https_preserves_flash
61
    get :set_flash
62
    get :b
63
    assert_response :redirect
64
    assert_equal "bar", flash[:foo]
65
  end
66
  
67
  def test_not_redirecting_to_https_does_not_preserve_the_flash
68
    get :set_flash
69
    get :d
70
    assert_response :success
71
    assert_nil flash[:foo]
72
  end
73
  
74
  def test_redirect_to_http_preserves_flash
75
    get :set_flash
76
    @request.env['HTTPS'] = "on"
77
    get :d
78
    assert_response :redirect
79
    assert_equal "bar", flash[:foo]
80
  end
81
  
82
  def test_not_redirecting_to_http_does_not_preserve_the_flash
83
    get :set_flash
84
    @request.env['HTTPS'] = "on"
85
    get :a
86
    assert_response :success
87
    assert_nil flash[:foo]
88
  end
89
  
90
  def test_required_without_ssl
91
    assert_not_equal "on", @request.env["HTTPS"]
92
    get :a
93
    assert_response :redirect
94
    assert_match %r{^https://}, @response.headers['Location']
95
    get :b
96
    assert_response :redirect
97
    assert_match %r{^https://}, @response.headers['Location']
98
  end
99
  
100
  def test_required_with_ssl
101
    @request.env['HTTPS'] = "on"
102
    get :a
103
    assert_response :success
104
    get :b
105
    assert_response :success
106
  end
107

  
108
  def test_disallowed_without_ssl
109
    assert_not_equal "on", @request.env["HTTPS"]
110
    get :d
111
    assert_response :success
112
  end
113

  
114
  def test_disallowed_with_ssl
115
    @request.env['HTTPS'] = "on"
116
    get :d
117
    assert_response :redirect
118
    assert_match %r{^http://}, @response.headers['Location']
119
  end
120

  
121
  def test_allowed_without_ssl
122
    assert_not_equal "on", @request.env["HTTPS"]
123
    get :c
124
    assert_response :success
125
  end
126

  
127
  def test_allowed_with_ssl
128
    @request.env['HTTPS'] = "on"
129
    get :c
130
    assert_response :success
131
  end
132
end
0
-