sslrequirement 1.1.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
data/.gitignore ADDED
@@ -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
data/Rakefile ADDED
@@ -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 = "sslrequirement"
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 = 'nathan@yardsticksoftware.com'
14
+ gemspec.homepage = 'http://github.com/yardstick/ssl_requirement'
15
+ gemspec.authors = ['RailsJedi', 'David Heinemeier Hansson', 'jcnetdev', 'bcurren', 'bmpercy','revo','nathany']
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.1.1
data/init.rb ADDED
@@ -0,0 +1,2 @@
1
+ require File.dirname(__FILE__) + "/rails/init"
2
+
@@ -0,0 +1,144 @@
1
+ require "#{File.dirname(__FILE__)}/url_rewriter"
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
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
+
44
+ def self.included(controller)
45
+ controller.extend(ClassMethods)
46
+ controller.before_filter(:ensure_proper_protocol)
47
+ end
48
+
49
+ def self.disable_ssl_check?
50
+ @@disable_ssl_check ||= false
51
+ end
52
+
53
+ def self.disable_ssl_check=(value)
54
+ @@disable_ssl_check = value
55
+ end
56
+
57
+ module ClassMethods
58
+ # Specifies that the named actions requires an SSL connection to be performed (which is enforced by ensure_proper_protocol).
59
+ def ssl_required(*actions)
60
+ write_inheritable_array(:ssl_required_actions, actions)
61
+ end
62
+
63
+ def ssl_exceptions(*actions)
64
+ write_inheritable_array(:ssl_required_except_actions, actions)
65
+ end
66
+
67
+ def ssl_allowed(*actions)
68
+ write_inheritable_array(:ssl_allowed_actions, actions)
69
+ end
70
+ end
71
+
72
+ protected
73
+ # Returns true if the current action is supposed to run as SSL
74
+ def ssl_required?
75
+ required = (self.class.read_inheritable_attribute(:ssl_required_actions) || [])
76
+ except = self.class.read_inheritable_attribute(:ssl_required_except_actions)
77
+
78
+ unless except
79
+ required.include?(action_name.to_sym)
80
+ else
81
+ !except.include?(action_name.to_sym)
82
+ end
83
+ end
84
+
85
+ def ssl_allowed?
86
+ (self.class.read_inheritable_attribute(:ssl_allowed_actions) || []).include?(action_name.to_sym)
87
+ end
88
+
89
+ # normal ports are the ports used when no port is specified by the user to the browser
90
+ # i.e. 80 if the protocol is http, 443 is the protocol is https
91
+ NORMAL_PORTS = [80, 443]
92
+
93
+ private
94
+ def ensure_proper_protocol
95
+ return true if SslRequirement.disable_ssl_check?
96
+ return true if ssl_allowed?
97
+
98
+ if ssl_required? && !request.ssl?
99
+ redirect_to determine_redirect_url(request, true)
100
+ flash.keep
101
+ return false
102
+ elsif request.ssl? && !ssl_required?
103
+ redirect_to determine_redirect_url(request, false)
104
+ flash.keep
105
+ return false
106
+ end
107
+ end
108
+
109
+ def determine_redirect_url(request, ssl)
110
+ protocol = ssl ? "https" : "http"
111
+ "#{protocol}://#{determine_host_and_port(request, ssl)}#{request.request_uri}"
112
+ end
113
+
114
+ def determine_host_and_port(request, ssl)
115
+ request_host = request.host
116
+ request_port = request.port
117
+
118
+ if ssl
119
+ "#{(ssl_host || request_host)}#{determine_port_string(request_port)}"
120
+ else
121
+ "#{(non_ssl_host || request_host)}#{determine_port_string(request_port)}"
122
+ end
123
+ end
124
+
125
+ def self.determine_host(host)
126
+ if host.is_a?(Proc) || host.respond_to?(:call)
127
+ host.call
128
+ else
129
+ host
130
+ end
131
+ end
132
+
133
+ def determine_port_string(port)
134
+ unless port_normal?(port)
135
+ ":#{port}"
136
+ else
137
+ ""
138
+ end
139
+ end
140
+
141
+ def port_normal?(port)
142
+ NORMAL_PORTS.include?(port)
143
+ end
144
+ end
@@ -0,0 +1,49 @@
1
+ require 'action_controller/url_rewriter'
2
+
3
+ module ActionController
4
+ class UrlRewriter
5
+
6
+ # Add a secure option to the rewrite method.
7
+ def rewrite_with_secure_option(options = {})
8
+ secure = options.delete(:secure)
9
+
10
+ # if secure && ssl check is not disabled, convert to full url with https
11
+ if !secure.nil? && !SslRequirement.disable_ssl_check?
12
+ if secure == true || secure == 1 || secure.to_s.downcase == "true"
13
+ options.merge!({
14
+ :only_path => false,
15
+ :protocol => 'https'
16
+ })
17
+
18
+ # if we've been told to use different host for ssl, use it
19
+ unless SslRequirement.ssl_host.nil?
20
+ options.merge! :host => SslRequirement.ssl_host
21
+ end
22
+
23
+ # make it non-ssl and use specified options
24
+ else
25
+ options.merge!({
26
+ :protocol => 'http'
27
+ })
28
+ end
29
+ end
30
+
31
+ rewrite_without_secure_option(options)
32
+ end
33
+
34
+ # if full URL is requested for http and we've been told to use a
35
+ # non-ssl host override, then use it
36
+ def rewrite_with_non_ssl_host(options)
37
+ if !options[:only_path] && !SslRequirement.non_ssl_host.nil?
38
+ if !(/^https/ =~ (options[:protocol] || @request.protocol))
39
+ options.merge! :host => SslRequirement.non_ssl_host
40
+ end
41
+ end
42
+ rewrite_without_non_ssl_host(options)
43
+ end
44
+
45
+ # want with_secure_option to get run first (so chain it last)
46
+ alias_method_chain :rewrite, :non_ssl_host
47
+ alias_method_chain :rewrite, :secure_option
48
+ end
49
+ end
data/rails/init.rb ADDED
@@ -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,79 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: sslrequirement
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 1
7
+ - 1
8
+ - 1
9
+ version: 1.1.1
10
+ platform: ruby
11
+ authors:
12
+ - RailsJedi
13
+ - David Heinemeier Hansson
14
+ - jcnetdev
15
+ - bcurren
16
+ - bmpercy
17
+ - revo
18
+ - nathany
19
+ autorequire:
20
+ bindir: bin
21
+ cert_chain: []
22
+
23
+ date: 2010-04-07 00:00:00 -06:00
24
+ default_executable:
25
+ dependencies: []
26
+
27
+ 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.
28
+ email: nathan@yardsticksoftware.com
29
+ executables: []
30
+
31
+ extensions: []
32
+
33
+ extra_rdoc_files:
34
+ - README
35
+ files:
36
+ - .gitignore
37
+ - README
38
+ - Rakefile
39
+ - VERSION
40
+ - init.rb
41
+ - lib/ssl_requirement.rb
42
+ - lib/url_rewriter.rb
43
+ - rails/init.rb
44
+ - shoulda_macros/ssl_requirement_macros.rb
45
+ - test/ssl_requirement_test.rb
46
+ - test/url_rewriter_test.rb
47
+ has_rdoc: true
48
+ homepage: http://github.com/yardstick/ssl_requirement
49
+ licenses: []
50
+
51
+ post_install_message:
52
+ rdoc_options:
53
+ - --charset=UTF-8
54
+ require_paths:
55
+ - lib
56
+ required_ruby_version: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - ">="
59
+ - !ruby/object:Gem::Version
60
+ segments:
61
+ - 0
62
+ version: "0"
63
+ required_rubygems_version: !ruby/object:Gem::Requirement
64
+ requirements:
65
+ - - ">="
66
+ - !ruby/object:Gem::Version
67
+ segments:
68
+ - 0
69
+ version: "0"
70
+ requirements: []
71
+
72
+ rubyforge_project:
73
+ rubygems_version: 1.3.6
74
+ signing_key:
75
+ specification_version: 3
76
+ summary: Allow controller actions to force SSL on specific parts of the site.
77
+ test_files:
78
+ - test/ssl_requirement_test.rb
79
+ - test/url_rewriter_test.rb