bartt-ssl_requirement 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ *.gem
data/README ADDED
@@ -0,0 +1,138 @@
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 < ActionController::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
+ If a majority (or all) of your actions require SSL, then use ssl_exceptions instead of ssl_required.
36
+ You can list out the actions that you do NOT want to be SSL protected. Calling ssl_exceptions without
37
+ any actions listed will make ALL actions SSL protected.
38
+
39
+ You can overwrite the protected method ssl_required? to rely on other things
40
+ than just the declarative specification. Say, only premium accounts get SSL.
41
+
42
+ For SSL domains that differ from the domain of the redirecting site, add the
43
+ following code to development.rb / test.rb / production.rb:
44
+
45
+ # Redirects to https://secure.example.com instead of the default
46
+ # https://www.example.com.
47
+ config.after_initialize do
48
+ SslRequirement.ssl_host = 'secure.example.com'
49
+ end
50
+
51
+ For non-SSL domains that differ from domain of redirecting site, add the
52
+ following code to development.rb / test.rb / production.rb:
53
+
54
+ # Redirects to http://nonsecure.example.com instead of the default
55
+ # http://www.example.com.
56
+ config.after_initialize do
57
+ SslRequirement.non_ssl_host = 'nonsecure.example.com'
58
+ end
59
+
60
+ You can also use a Proc to determine the ssl_host or non_ssl_host on the fly:
61
+
62
+ config.after_initialize do
63
+ SslRequirement.ssl_host = Proc.new do
64
+ 'secure.example.com'
65
+ end
66
+ end
67
+
68
+ You are able to turn disable ssl redirects by adding the following environment configuration file:
69
+
70
+ SslRequirement.disable_ssl_check = true
71
+
72
+ P.S.: Beware when you include the SslRequirement module. At the time of
73
+ inclusion, it'll add the before_filter that validates the declarations. Some
74
+ times you'll want to run other before_filters before that. They should then be
75
+ declared ahead of including this module.
76
+
77
+ SSL URL Helper
78
+ ==============
79
+ This plugin also adds a helper a :secure option to url_for and named_routes. This property
80
+ allows you to set a url as secure or not secure. It uses the disable_ssl_check to determine
81
+ if the option should be ignored or not so you can develop as normal. It also
82
+ will obey if you override SslRequirement.ssl_host or
83
+ SslRequirement.non_ssl_host (see above)
84
+
85
+ Here is an example of creating a secure url:
86
+
87
+ <%= url_for(:controller => "c", :action => "a", :secure => true) %>
88
+
89
+ If disable_ssl_check returns false url_for will return the following:
90
+
91
+ https://yoursite.com/c/a
92
+
93
+ Furthermore, you can use the secure option in a named route to create a secure form as follows:
94
+
95
+ <% form_tag session_path(:secure => true), :class => 'home_login' do -%>
96
+ <p>
97
+ <label for="name">Email</label>
98
+ <%= text_field_tag 'email', '', :class => 'text', :tabindex => 1 %>
99
+ </p>
100
+ <p>
101
+ <label for="password">Password</label>
102
+ <%= password_field_tag 'password', '', :class => 'text', :tabindex => 2 %>
103
+ </p>
104
+ <p>
105
+ <%= submit_tag "Login", :id => 'login_submit', :value => "", :alt => "Login" %>
106
+ </p>
107
+ <% end -%>
108
+
109
+ Testing with Shoulda
110
+ ====================
111
+
112
+ If you are using Shoulda, a few contexts and macros are provided:
113
+
114
+ class RegistrationsControllerTest < ActionController::TestCase
115
+ without_ssl_context do
116
+ context "GET to :new" do
117
+ setup do
118
+ get :new
119
+ end
120
+ should_redirect_to_ssl
121
+ end
122
+ end
123
+
124
+ with_ssl_context do
125
+ context "GET to :new" do
126
+ setup do
127
+ get :new
128
+ end
129
+ # your usual testing goes here
130
+ end
131
+ end
132
+ end
133
+
134
+
135
+ Copyright
136
+ =========
137
+
138
+ Copyright (c) 2005 David Heinemeier Hansson, released under the MIT license
@@ -0,0 +1,26 @@
1
+ require 'rake'
2
+ require 'rake/testtask'
3
+
4
+ desc "Run the unit tests"
5
+ task :default => 'test'
6
+
7
+ begin
8
+ require 'jeweler'
9
+ Jeweler::Tasks.new do |gemspec|
10
+ gemspec.name = "bartt-ssl_requirement"
11
+ gemspec.summary = "Allow controller actions to force SSL on specific parts of the site."
12
+ gemspec.description = "SSL requirement adds a declarative way of specifying that certain actions should only be allowed to run under SSL, and if they're accessed without it, they should be redirected."
13
+ gemspec.email = 'bartt@vurve.com'
14
+ gemspec.homepage = 'http://github.com/bartt/ssl_requirement'
15
+ gemspec.authors = ['RailsJedi', 'David Heinemeier Hansson', 'jcnetdev', 'bcurren', 'bmpercy','revo','nathany', 'bartt']
16
+ end
17
+ rescue LoadError
18
+ puts "Jeweler not available. Install it with: gem install jeweler"
19
+ end
20
+
21
+ Rake::TestTask.new(:test) do |t|
22
+ t.pattern = 'test/**/*_test.rb'
23
+ t.ruby_opts << '-rubygems'
24
+ t.libs << 'test'
25
+ t.verbose = true
26
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 1.2.0
@@ -0,0 +1,52 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{bartt-ssl_requirement}
8
+ s.version = "1.2.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["RailsJedi", "David Heinemeier Hansson", "jcnetdev", "bcurren", "bmpercy", "revo", "nathany", "bartt"]
12
+ s.date = %q{2010-04-26}
13
+ s.description = %q{SSL requirement adds a declarative way of specifying that certain actions should only be allowed to run under SSL, and if they're accessed without it, they should be redirected.}
14
+ s.email = %q{bartt@vurve.com}
15
+ s.extra_rdoc_files = [
16
+ "README"
17
+ ]
18
+ s.files = [
19
+ ".gitignore",
20
+ "README",
21
+ "Rakefile",
22
+ "VERSION",
23
+ "bartt-ssl_requirement.gemspec",
24
+ "init.rb",
25
+ "lib/ssl_requirement.rb",
26
+ "lib/url_for.rb",
27
+ "rails/init.rb",
28
+ "shoulda_macros/ssl_requirement_macros.rb",
29
+ "test/ssl_requirement_test.rb",
30
+ "test/url_for_test.rb"
31
+ ]
32
+ s.homepage = %q{http://github.com/bartt/ssl_requirement}
33
+ s.rdoc_options = ["--charset=UTF-8"]
34
+ s.require_paths = ["lib"]
35
+ s.rubygems_version = %q{1.3.6}
36
+ s.summary = %q{Allow controller actions to force SSL on specific parts of the site.}
37
+ s.test_files = [
38
+ "test/ssl_requirement_test.rb",
39
+ "test/url_for_test.rb"
40
+ ]
41
+
42
+ if s.respond_to? :specification_version then
43
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
44
+ s.specification_version = 3
45
+
46
+ if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
47
+ else
48
+ end
49
+ else
50
+ end
51
+ end
52
+
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ require File.dirname(__FILE__) + "/rails/init"
2
+
@@ -0,0 +1,141 @@
1
+ require "#{File.dirname(__FILE__)}/url_for"
2
+
3
+ # Copyright (c) 2005 David Heinemeier Hansson
4
+ #
5
+ # Permission is hereby granted, free of charge, to any person obtaining
6
+ # a copy of this software and associated documentation files (the
7
+ # "Software"), to deal in the Software without restriction, including
8
+ # without limitation the rights to use, copy, modify, merge, publish,
9
+ # distribute, sublicense, and/or sell copies of the Software, and to
10
+ # permit persons to whom the Software is furnished to do so, subject to
11
+ # the following conditions:
12
+ #
13
+ # The above copyright notice and this permission notice shall be
14
+ # included in all copies or substantial portions of the Software.
15
+ #
16
+ # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
+ # EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
+ # MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
+ # NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
+ # LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
+ # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
+ # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
+ module SslRequirement
24
+ mattr_writer :ssl_host, :non_ssl_host, :disable_ssl_check
25
+
26
+ def self.ssl_host
27
+ determine_host(@@ssl_host)
28
+ end
29
+
30
+ def self.non_ssl_host
31
+ determine_host(@@non_ssl_host)
32
+ end
33
+
34
+ # mattr_reader would generate both ssl_host and self.ssl_host
35
+ def ssl_host
36
+ SslRequirement.ssl_host
37
+ end
38
+
39
+ def non_ssl_host
40
+ SslRequirement.non_ssl_host
41
+ end
42
+
43
+ def self.disable_ssl_check?
44
+ @@disable_ssl_check ||= false
45
+ end
46
+
47
+
48
+ # called when Module is mixed in
49
+ def self.included(controller)
50
+ controller.extend(ClassMethods)
51
+ controller.before_filter(:ensure_proper_protocol)
52
+ end
53
+
54
+ module ClassMethods
55
+ # Specifies that the named actions requires an SSL connection to be performed (which is enforced by ensure_proper_protocol).
56
+ def ssl_required(*actions)
57
+ write_inheritable_array(:ssl_required_actions, actions)
58
+ end
59
+
60
+ def ssl_exceptions(*actions)
61
+ write_inheritable_array(:ssl_required_except_actions, actions)
62
+ end
63
+
64
+ def ssl_allowed(*actions)
65
+ write_inheritable_array(:ssl_allowed_actions, actions)
66
+ end
67
+ end
68
+
69
+ protected
70
+ # Returns true if the current action is supposed to run as SSL
71
+ def ssl_required?
72
+ required = (self.class.read_inheritable_attribute(:ssl_required_actions) || [])
73
+ except = self.class.read_inheritable_attribute(:ssl_required_except_actions)
74
+
75
+ unless except
76
+ required.include?(action_name.to_sym)
77
+ else
78
+ !except.include?(action_name.to_sym)
79
+ end
80
+ end
81
+
82
+ def ssl_allowed?
83
+ (self.class.read_inheritable_attribute(:ssl_allowed_actions) || []).include?(action_name.to_sym)
84
+ end
85
+
86
+ # normal ports are the ports used when no port is specified by the user to the browser
87
+ # i.e. 80 if the protocol is http, 443 is the protocol is https
88
+ NORMAL_PORTS = [80, 443]
89
+
90
+ private
91
+ def ensure_proper_protocol
92
+ return true if SslRequirement.disable_ssl_check?
93
+ return true if ssl_allowed?
94
+
95
+ if ssl_required? && !request.ssl?
96
+ redirect_to determine_redirect_url(request, true)
97
+ flash.keep
98
+ return false
99
+ elsif request.ssl? && !ssl_required?
100
+ redirect_to determine_redirect_url(request, false)
101
+ flash.keep
102
+ return false
103
+ end
104
+ end
105
+
106
+ def determine_redirect_url(request, ssl)
107
+ protocol = ssl ? "https" : "http"
108
+ "#{protocol}://#{determine_host_and_port(request, ssl)}#{request.request_uri}"
109
+ end
110
+
111
+ def determine_host_and_port(request, ssl)
112
+ request_host = request.host
113
+ request_port = request.port
114
+
115
+ if ssl
116
+ "#{(ssl_host || request_host)}#{determine_port_string(request_port)}"
117
+ else
118
+ "#{(non_ssl_host || request_host)}#{determine_port_string(request_port)}"
119
+ end
120
+ end
121
+
122
+ def self.determine_host(host)
123
+ if host.is_a?(Proc) || host.respond_to?(:call)
124
+ host.call
125
+ else
126
+ host
127
+ end
128
+ end
129
+
130
+ def determine_port_string(port)
131
+ unless port_normal?(port)
132
+ ":#{port}"
133
+ else
134
+ ""
135
+ end
136
+ end
137
+
138
+ def port_normal?(port)
139
+ NORMAL_PORTS.include?(port)
140
+ end
141
+ end
@@ -0,0 +1,51 @@
1
+ require 'action_dispatch/routing/route_set'
2
+
3
+ module ActionDispatch
4
+ module Routing
5
+ class RouteSet
6
+
7
+ # Add a secure option to the rewrite method.
8
+ def url_for_with_secure_option(options = {})
9
+ secure = options.delete(:secure)
10
+
11
+ # if secure && ssl check is not disabled, convert to full url with https
12
+ if !secure.nil? && !SslRequirement.disable_ssl_check?
13
+ if secure == true || secure == 1 || secure.to_s.downcase == "true"
14
+ options.merge!({
15
+ :only_path => false,
16
+ :protocol => 'https'
17
+ })
18
+
19
+ # if we've been told to use different host for ssl, use it
20
+ unless SslRequirement.ssl_host.nil?
21
+ options.merge! :host => SslRequirement.ssl_host
22
+ end
23
+
24
+ # make it non-ssl and use specified options
25
+ else
26
+ options.merge!({
27
+ :protocol => 'http'
28
+ })
29
+ end
30
+ end
31
+
32
+ url_for_without_secure_option(options)
33
+ end
34
+
35
+ # if full URL is requested for http and we've been told to use a
36
+ # non-ssl host override, then use it
37
+ def url_for_with_non_ssl_host(options)
38
+ if !options[:only_path] && !SslRequirement.non_ssl_host.nil?
39
+ if !(/^https/ =~ (options[:protocol] || @request.protocol))
40
+ options.merge! :host => SslRequirement.non_ssl_host
41
+ end
42
+ end
43
+ url_for_without_non_ssl_host(options)
44
+ end
45
+
46
+ # want with_secure_option to get run first (so chain it last)
47
+ alias_method_chain :url_for, :non_ssl_host
48
+ alias_method_chain :url_for, :secure_option
49
+ end
50
+ end
51
+ end
@@ -0,0 +1 @@
1
+ require 'ssl_requirement'
@@ -0,0 +1,31 @@
1
+ Test::Unit::TestCase.class_eval do
2
+ def self.without_ssl_context
3
+ context "without ssl" do
4
+ setup do
5
+ @request.env['HTTPS'] = nil
6
+ end
7
+
8
+ context "" do
9
+ yield
10
+ end
11
+ end
12
+ end
13
+
14
+ def self.with_ssl_context
15
+ context "with ssl" do
16
+ setup do
17
+ @request.env['HTTPS'] = 'on'
18
+ end
19
+
20
+ context "" do
21
+ yield
22
+ end
23
+ end
24
+ end
25
+
26
+ def self.should_redirect_to_ssl
27
+ should 'redirect to ssl' do
28
+ assert_redirected_to "https://" + @request.host + @request.request_uri
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,342 @@
1
+ require 'set'
2
+ require 'rubygems'
3
+ require 'active_support'
4
+ begin
5
+ require 'action_controller'
6
+ rescue LoadError
7
+ if ENV['ACTIONCONTROLLER_PATH'].nil?
8
+ abort <<MSG
9
+ Please set the ACTIONCONTROLLER_PATH environment variable to the directory
10
+ containing the action_controller.rb file.
11
+ MSG
12
+ else
13
+ $LOAD_PATH.unshift ENV['ACTIONCONTROLLER_PATH']
14
+ begin
15
+ require 'action_controller'
16
+ rescue LoadError
17
+ abort "ActionController could not be found."
18
+ end
19
+ end
20
+ end
21
+
22
+ require 'action_controller/test_process'
23
+ require 'test/unit'
24
+ require "#{File.dirname(__FILE__)}/../lib/ssl_requirement"
25
+
26
+ ActionController::Base.logger = nil
27
+ ActionController::Routing::Routes.reload rescue nil
28
+
29
+ # several test controllers to cover different combinations of requiring/
30
+ # allowing/exceptions-ing SSL for controller actions
31
+
32
+ # this first controller modifies the flash in every action so that flash
33
+ # set in set_flash is eventually expired (see NOTE below...)
34
+
35
+ class SslRequirementController < ActionController::Base
36
+ include SslRequirement
37
+
38
+ ssl_required :a, :b
39
+ ssl_allowed :c
40
+
41
+ def a
42
+ flash[:abar] = "foo"
43
+ render :nothing => true
44
+ end
45
+
46
+ def b
47
+ flash[:bbar] = "foo"
48
+ render :nothing => true
49
+ end
50
+
51
+ def c
52
+ flash[:cbar] = "foo"
53
+ render :nothing => true
54
+ end
55
+
56
+ def d
57
+ flash[:dbar] = "foo"
58
+ render :nothing => true
59
+ end
60
+
61
+ def set_flash
62
+ flash[:foo] = "bar"
63
+ end
64
+ end
65
+
66
+ class SslExceptionController < ActionController::Base
67
+ include SslRequirement
68
+
69
+ ssl_required :a
70
+ ssl_exceptions :b
71
+ ssl_allowed :d
72
+
73
+ def a
74
+ render :nothing => true
75
+ end
76
+
77
+ def b
78
+ render :nothing => true
79
+ end
80
+
81
+ def c
82
+ render :nothing => true
83
+ end
84
+
85
+ def d
86
+ render :nothing => true
87
+ end
88
+
89
+ end
90
+
91
+ class SslAllActionsController < ActionController::Base
92
+ include SslRequirement
93
+
94
+ ssl_exceptions
95
+
96
+ def a
97
+ render :nothing => true
98
+ end
99
+
100
+ end
101
+
102
+ # NOTE: The only way I could get the flash tests to work under Rails 2.3.2
103
+ # (without resorting to IntegrationTest with some artificial session
104
+ # store) was to use TestCase. In TestCases, it appears that flash
105
+ # messages are effectively persisted in session after the last controller
106
+ # action that consumed them...so that when the TestCase inspects
107
+ # the FlashHash, it will find the flash still populated, even though
108
+ # the subsequent controller action won't see it.
109
+ #
110
+ # In addition, if no changes are made to flash in subsequent requests, the
111
+ # flash is persisted forever. But if subsequent controller actions add to
112
+ # flash, the older flash messages eventually disappear.
113
+ #
114
+ # As a result, the flash-related tests now make two requests after the
115
+ # set_flash, each of these requests is also modifying flash. flash is
116
+ # inspected after the second request returns.
117
+ #
118
+ # This feels a little hacky, so if anyone can improve it, please do so!
119
+
120
+ class SslRequirementTest < ActionController::TestCase
121
+ def setup
122
+ @controller = SslRequirementController.new
123
+ @ssl_host_override = 'www.example.com:80443'
124
+ @non_ssl_host_override = 'www.example.com:8080'
125
+ end
126
+
127
+ # port preservation tests
128
+
129
+ def test_redirect_to_https_preserves_non_normal_port
130
+ assert_not_equal "on", @request.env["HTTPS"]
131
+ @request.port = 4567
132
+ get :b
133
+ assert_response :redirect
134
+ assert_match %r{^https://.*:4567/}, @response.headers['Location']
135
+ end
136
+
137
+ def test_redirect_to_https_does_not_preserve_normal_port
138
+ assert_not_equal "on", @request.env["HTTPS"]
139
+ get :b
140
+ assert_response :redirect
141
+ assert_match %r{^https://.*[^:]/}, @response.headers['Location']
142
+ end
143
+
144
+ # flash-related tests
145
+
146
+ def test_redirect_to_https_preserves_flash
147
+ assert_not_equal "on", @request.env["HTTPS"]
148
+ get :set_flash
149
+ get :b
150
+ assert_response :redirect # check redirect happens (flash still set)
151
+ get :b # get again to flush flash
152
+ assert_response :redirect # make sure it happens again
153
+ assert_equal "bar", flash[:foo] # the flash would be gone now if no redirect
154
+ end
155
+
156
+ def test_not_redirecting_to_https_does_not_preserve_the_flash
157
+ assert_not_equal "on", @request.env["HTTPS"]
158
+ get :set_flash
159
+ get :d
160
+ assert_response :success # check no redirect (flash still set)
161
+ get :d # get again to flush flash
162
+ assert_response :success # check no redirect
163
+ assert_nil flash[:foo] # the flash should be gone now
164
+ end
165
+
166
+ def test_redirect_to_http_preserves_flash
167
+ get :set_flash
168
+ @request.env['HTTPS'] = "on"
169
+ get :d
170
+ assert_response :redirect # check redirect happens (flash still set)
171
+ get :d # get again to flush flash
172
+ assert_response :redirect # make sure redirect happens
173
+ assert_equal "bar", flash[:foo] # flash would be gone now if no redirect
174
+ end
175
+
176
+ def test_not_redirecting_to_http_does_not_preserve_the_flash
177
+ get :set_flash
178
+ @request.env['HTTPS'] = "on"
179
+ get :a
180
+ assert_response :success # no redirect (flash still set)
181
+ get :a # get again to flush flash
182
+ assert_response :success # no redirect
183
+ assert_nil flash[:foo] # flash should be gone now
184
+ end
185
+
186
+ # ssl required/allowed/exceptions testing
187
+
188
+ def test_required_without_ssl
189
+ assert_not_equal "on", @request.env["HTTPS"]
190
+ get :a
191
+ assert_response :redirect
192
+ assert_match %r{^https://}, @response.headers['Location']
193
+ get :b
194
+ assert_response :redirect
195
+ assert_match %r{^https://}, @response.headers['Location']
196
+ end
197
+
198
+ def test_required_with_ssl
199
+ @request.env['HTTPS'] = "on"
200
+ get :a
201
+ assert_response :success
202
+ get :b
203
+ assert_response :success
204
+ end
205
+
206
+ def test_disallowed_without_ssl
207
+ assert_not_equal "on", @request.env["HTTPS"]
208
+ get :d
209
+ assert_response :success
210
+ end
211
+
212
+ def test_ssl_exceptions_without_ssl
213
+ @controller = SslExceptionController.new
214
+ assert_not_equal "on", @request.env["HTTPS"]
215
+ get :a
216
+ assert_response :redirect
217
+ assert_match %r{^https://}, @response.headers['Location']
218
+ get :b
219
+ assert_response :success
220
+ get :c # c is not explicity in ssl_required, but it is not listed in ssl_exceptions
221
+ assert_response :redirect
222
+ assert_match %r{^https://}, @response.headers['Location']
223
+ end
224
+
225
+ def test_ssl_exceptions_with_ssl
226
+ @controller = SslExceptionController.new
227
+ @request.env['HTTPS'] = "on"
228
+ get :a
229
+ assert_response :success
230
+ get :c
231
+ assert_response :success
232
+ end
233
+
234
+ def test_ssl_all_actions_without_ssl
235
+ @controller = SslAllActionsController.new
236
+ get :a
237
+ assert_response :redirect
238
+ assert_match %r{^https://}, @response.headers['Location']
239
+ end
240
+
241
+ def test_disallowed_with_ssl
242
+ @request.env['HTTPS'] = "on"
243
+ get :d
244
+ assert_response :redirect
245
+ assert_match %r{^http://}, @response.headers['Location']
246
+ end
247
+
248
+ def test_allowed_without_ssl
249
+ assert_not_equal "on", @request.env["HTTPS"]
250
+ get :c
251
+ assert_response :success
252
+ end
253
+
254
+ def test_allowed_with_ssl
255
+ @request.env['HTTPS'] = "on"
256
+ get :c
257
+ assert_response :success
258
+ end
259
+
260
+ def test_disable_ssl_check
261
+ SslRequirement.disable_ssl_check = true
262
+
263
+ assert_not_equal "on", @request.env["HTTPS"]
264
+ get :a
265
+ assert_response :success
266
+ get :b
267
+ assert_response :success
268
+ ensure
269
+ SslRequirement.disable_ssl_check = false
270
+ end
271
+
272
+ # testing overriding hostnames for ssl, non-ssl
273
+
274
+ # test for overriding (or not) the ssl_host and non_ssl_host variables
275
+ # using actions a (ssl required) and d (ssl not required or allowed)
276
+
277
+ def test_ssl_redirect_with_ssl_host
278
+ SslRequirement.ssl_host = @ssl_host_override
279
+ assert_not_equal "on", @request.env["HTTPS"]
280
+ get :a
281
+ assert_response :redirect
282
+ assert_match Regexp.new("^https://#{@ssl_host_override}"),
283
+ @response.headers['Location']
284
+ SslRequirement.ssl_host = nil
285
+ end
286
+
287
+ def test_ssl_redirect_without_ssl_host
288
+ SslRequirement.ssl_host = nil
289
+ assert_not_equal "on", @request.env["HTTPS"]
290
+ get :a
291
+ assert_response :redirect
292
+ assert_match Regexp.new("^https://"), @response.headers['Location']
293
+ assert_no_match Regexp.new("^https://#{@ssl_host_override}"),
294
+ @response.headers['Location']
295
+ end
296
+
297
+ def test_non_ssl_redirect_with_non_ssl_host
298
+ SslRequirement.non_ssl_host = @non_ssl_host_override
299
+ @request.env['HTTPS'] = 'on'
300
+ get :d
301
+ assert_response :redirect
302
+ assert_match Regexp.new("^http://#{@non_ssl_host_override}"),
303
+ @response.headers['Location']
304
+ SslRequirement.non_ssl_host = nil
305
+ end
306
+
307
+ def test_non_ssl_redirect_without_non_ssl_host
308
+ SslRequirement.non_ssl_host = nil
309
+ @request.env['HTTPS'] = 'on'
310
+ get :d
311
+ assert_response :redirect
312
+ assert_match Regexp.new("^http://"), @response.headers['Location']
313
+ assert_no_match Regexp.new("^http://#{@non_ssl_host_override}"),
314
+ @response.headers['Location']
315
+ end
316
+
317
+ # test ssl_host and ssl_non_host overrides with Procs
318
+
319
+ def test_ssl_redirect_with_ssl_host_proc
320
+ SslRequirement.ssl_host = Proc.new do
321
+ @ssl_host_override
322
+ end
323
+ assert_not_equal "on", @request.env["HTTPS"]
324
+ get :a
325
+ assert_response :redirect
326
+ assert_match Regexp.new("^https://#{@ssl_host_override}"),
327
+ @response.headers['Location']
328
+ SslRequirement.ssl_host = nil
329
+ end
330
+
331
+ def test_non_ssl_redirect_with_non_ssl_host_proc
332
+ SslRequirement.non_ssl_host = Proc.new do
333
+ @non_ssl_host_override
334
+ end
335
+ @request.env['HTTPS'] = 'on'
336
+ get :d
337
+ assert_response :redirect
338
+ assert_match Regexp.new("^http://#{@non_ssl_host_override}"),
339
+ @response.headers['Location']
340
+ SslRequirement.non_ssl_host = nil
341
+ end
342
+ end
@@ -0,0 +1,169 @@
1
+ $:.unshift(File.dirname(__FILE__) + '/../lib')
2
+
3
+ require 'rubygems'
4
+ require 'test/unit'
5
+ require 'action_controller'
6
+ require 'action_controller/test_process'
7
+
8
+ require "ssl_requirement"
9
+
10
+ # Show backtraces for deprecated behavior for quicker cleanup.
11
+ ActiveSupport::Deprecation.debug = true
12
+ ActionController::Base.logger = nil
13
+ ActionController::Routing::Routes.reload rescue nil
14
+
15
+ class UrlRewriterTest < Test::Unit::TestCase
16
+ def setup
17
+ @request = ActionController::TestRequest.new
18
+ @params = {}
19
+ @rewriter = ActionController::UrlRewriter.new(@request, @params)
20
+
21
+ @ssl_host_override = "www.example.com:80443"
22
+ @non_ssl_host_override = "www.example.com:8080"
23
+
24
+ SslRequirement.ssl_host = nil
25
+ SslRequirement.non_ssl_host = nil
26
+
27
+ # puts @url_rewriter.to_s
28
+ end
29
+
30
+ def test_rewrite_secure_false
31
+ SslRequirement.disable_ssl_check = false
32
+ assert_equal('http://test.host/c/a',
33
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :secure => false)
34
+ )
35
+ assert_equal('/c/a',
36
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :secure => false,
37
+ :only_path => true)
38
+ )
39
+
40
+ SslRequirement.disable_ssl_check = true
41
+ assert_equal('http://test.host/c/a',
42
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :secure => false)
43
+ )
44
+ assert_equal('/c/a',
45
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :secure => false,
46
+ :only_path => true)
47
+ )
48
+ end
49
+
50
+ def test_rewrite_secure_true
51
+ SslRequirement.disable_ssl_check = false
52
+ assert_equal('https://test.host/c/a',
53
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :secure => true)
54
+ )
55
+ assert_equal('https://test.host/c/a',
56
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :secure => true, :only_path => true)
57
+ )
58
+
59
+ SslRequirement.disable_ssl_check = true
60
+ assert_equal('http://test.host/c/a',
61
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :secure => true)
62
+ )
63
+ assert_equal('/c/a',
64
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :secure => true, :only_path => true)
65
+ )
66
+ end
67
+
68
+ def test_rewrite_secure_not_specified
69
+ SslRequirement.disable_ssl_check = false
70
+ assert_equal('http://test.host/c/a',
71
+ @rewriter.rewrite(:controller => 'c', :action => 'a')
72
+ )
73
+ assert_equal('/c/a',
74
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :only_path => true)
75
+ )
76
+
77
+ SslRequirement.disable_ssl_check = true
78
+ assert_equal('http://test.host/c/a',
79
+ @rewriter.rewrite(:controller => 'c', :action => 'a')
80
+ )
81
+ assert_equal('/c/a',
82
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :only_path => true)
83
+ )
84
+ end
85
+
86
+ # tests for ssl_host overriding
87
+
88
+ def test_rewrite_secure_with_ssl_host
89
+ SslRequirement.disable_ssl_check = false
90
+ SslRequirement.ssl_host = @ssl_host_override
91
+ assert_equal("https://#{@ssl_host_override}/c/a",
92
+ @rewriter.rewrite(:controller => 'c', :action => 'a',
93
+ :secure => true))
94
+ assert_equal("https://#{@ssl_host_override}/c/a",
95
+ @rewriter.rewrite(:controller => 'c', :action => 'a',
96
+ :secure => true, :only_path => true))
97
+ SslRequirement.ssl_host = nil
98
+ end
99
+
100
+ def test_rewrite_non_secure_with_non_ssl_host
101
+ SslRequirement.disable_ssl_check = false
102
+ SslRequirement.non_ssl_host = @non_ssl_host_override
103
+
104
+ # with secure option
105
+ assert_equal("http://#{@non_ssl_host_override}/c/a",
106
+ @rewriter.rewrite(:controller => 'c', :action => 'a',
107
+ :secure => false))
108
+ assert_equal("/c/a",
109
+ @rewriter.rewrite(:controller => 'c', :action => 'a',
110
+ :secure => false, :only_path => true))
111
+
112
+ # without secure option
113
+ assert_equal("http://#{@non_ssl_host_override}/c/a",
114
+ @rewriter.rewrite(:controller => 'c', :action => 'a'))
115
+ assert_equal("/c/a",
116
+ @rewriter.rewrite(:controller => 'c', :action => 'a',
117
+ :only_path => true))
118
+ SslRequirement.non_ssl_host = nil
119
+ end
120
+
121
+ def test_rewrite_non_secure_with_non_ssl_host_disable_check
122
+ SslRequirement.disable_ssl_check = true
123
+ SslRequirement.non_ssl_host = @non_ssl_host_override
124
+
125
+ # with secure option
126
+ assert_equal("http://#{@non_ssl_host_override}/c/a",
127
+ @rewriter.rewrite(:controller => 'c', :action => 'a',
128
+ :secure => false))
129
+ assert_equal("/c/a",
130
+ @rewriter.rewrite(:controller => 'c', :action => 'a',
131
+ :secure => false, :only_path => true))
132
+
133
+ # without secure option
134
+ assert_equal("http://#{@non_ssl_host_override}/c/a",
135
+ @rewriter.rewrite(:controller => 'c', :action => 'a'))
136
+ assert_equal("/c/a",
137
+ @rewriter.rewrite(:controller => 'c', :action => 'a',
138
+ :only_path => true))
139
+ SslRequirement.non_ssl_host = nil
140
+ end
141
+
142
+ # tests for ssl_host overriding with Procs
143
+
144
+ def test_rewrite_secure_with_ssl_host_proc
145
+ SslRequirement.disable_ssl_check = false
146
+ SslRequirement.ssl_host = Proc.new do
147
+ @ssl_host_override
148
+ end
149
+ assert_equal("https://#{@ssl_host_override}/c/a",
150
+ @rewriter.rewrite(:controller => 'c', :action => 'a',
151
+ :secure => true))
152
+ SslRequirement.ssl_host = nil
153
+ end
154
+
155
+ def test_rewrite_non_secure_with_non_ssl_host_proc
156
+ SslRequirement.disable_ssl_check = false
157
+ SslRequirement.non_ssl_host = Proc.new do
158
+ @non_ssl_host_override
159
+ end
160
+ # with secure option
161
+ assert_equal("http://#{@non_ssl_host_override}/c/a",
162
+ @rewriter.rewrite(:controller => 'c', :action => 'a',
163
+ :secure => false))
164
+ # without secure option
165
+ assert_equal("http://#{@non_ssl_host_override}/c/a",
166
+ @rewriter.rewrite(:controller => 'c', :action => 'a'))
167
+ SslRequirement.non_ssl_host = nil
168
+ end
169
+ end
metadata ADDED
@@ -0,0 +1,81 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: bartt-ssl_requirement
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 2
8
+ - 0
9
+ version: 1.2.0
10
+ platform: ruby
11
+ authors:
12
+ - RailsJedi
13
+ - David Heinemeier Hansson
14
+ - jcnetdev
15
+ - bcurren
16
+ - bmpercy
17
+ - revo
18
+ - nathany
19
+ - bartt
20
+ autorequire:
21
+ bindir: bin
22
+ cert_chain: []
23
+
24
+ date: 2010-04-26 00:00:00 -07:00
25
+ default_executable:
26
+ dependencies: []
27
+
28
+ description: SSL requirement adds a declarative way of specifying that certain actions should only be allowed to run under SSL, and if they're accessed without it, they should be redirected.
29
+ email: bartt@vurve.com
30
+ executables: []
31
+
32
+ extensions: []
33
+
34
+ extra_rdoc_files:
35
+ - README
36
+ files:
37
+ - .gitignore
38
+ - README
39
+ - Rakefile
40
+ - VERSION
41
+ - bartt-ssl_requirement.gemspec
42
+ - init.rb
43
+ - lib/ssl_requirement.rb
44
+ - lib/url_for.rb
45
+ - rails/init.rb
46
+ - shoulda_macros/ssl_requirement_macros.rb
47
+ - test/ssl_requirement_test.rb
48
+ - test/url_for_test.rb
49
+ has_rdoc: true
50
+ homepage: http://github.com/bartt/ssl_requirement
51
+ licenses: []
52
+
53
+ post_install_message:
54
+ rdoc_options:
55
+ - --charset=UTF-8
56
+ require_paths:
57
+ - lib
58
+ required_ruby_version: !ruby/object:Gem::Requirement
59
+ requirements:
60
+ - - ">="
61
+ - !ruby/object:Gem::Version
62
+ segments:
63
+ - 0
64
+ version: "0"
65
+ required_rubygems_version: !ruby/object:Gem::Requirement
66
+ requirements:
67
+ - - ">="
68
+ - !ruby/object:Gem::Version
69
+ segments:
70
+ - 0
71
+ version: "0"
72
+ requirements: []
73
+
74
+ rubyforge_project:
75
+ rubygems_version: 1.3.6
76
+ signing_key:
77
+ specification_version: 3
78
+ summary: Allow controller actions to force SSL on specific parts of the site.
79
+ test_files:
80
+ - test/ssl_requirement_test.rb
81
+ - test/url_for_test.rb