bcurren-ssl_requirement 1.0.4 → 1.0.6

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/README CHANGED
@@ -48,6 +48,15 @@ config.after_initialize do
48
48
  SslRequirement.ssl_host = 'secure.example.com'
49
49
  end
50
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
+
51
60
  You are able to turn disable ssl redirects by adding the following environment configuration file:
52
61
  SslRequirement.disable_ssl_check = true
53
62
 
@@ -60,7 +69,9 @@ SSL URL Helper
60
69
  ==============
61
70
  This plugin also adds a helper a :secure option to url_for and named_routes. This property
62
71
  allows you to set a url as secure or not secure. It uses the disable_ssl_check to determine
63
- if the option should be ignored or not so you can develop as normal.
72
+ if the option should be ignored or not so you can develop as normal. It also
73
+ will obey if you override SslRequirement.ssl_host or
74
+ SslRequirement.non_ssl_host (see above)
64
75
 
65
76
  Here is an example of creating a secure url:
66
77
 
@@ -21,11 +21,7 @@ require "#{File.dirname(__FILE__)}/url_rewriter"
21
21
  # OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
22
  # WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
23
  module SslRequirement
24
- mattr_reader :ssl_host
25
-
26
- def self.ssl_host=(host)
27
- @@ssl_host = host
28
- end
24
+ mattr_accessor :ssl_host, :non_ssl_host
29
25
 
30
26
  def self.included(controller)
31
27
  controller.extend(ClassMethods)
@@ -82,7 +78,7 @@ module SslRequirement
82
78
  flash.keep
83
79
  return false
84
80
  elsif request.ssl? && !ssl_required?
85
- redirect_to "http://" + request.host + request.request_uri
81
+ redirect_to "http://" + (non_ssl_host || request.host) + request.request_uri
86
82
  flash.keep
87
83
  return false
88
84
  end
data/lib/url_rewriter.rb CHANGED
@@ -6,22 +6,44 @@ module ActionController
6
6
  # Add a secure option to the rewrite method.
7
7
  def rewrite_with_secure_option(options = {})
8
8
  secure = options.delete(:secure)
9
+
10
+ # if secure && ssl check is not disabled, convert to full url with https
9
11
  if !secure.nil? && !SslRequirement.disable_ssl_check?
10
12
  if secure == true || secure == 1 || secure.to_s.downcase == "true"
11
13
  options.merge!({
12
14
  :only_path => false,
13
15
  :protocol => 'https'
14
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
15
24
  else
16
25
  options.merge!({
17
- :only_path => false,
18
26
  :protocol => 'http'
19
27
  })
20
28
  end
21
29
  end
22
-
30
+
23
31
  rewrite_without_secure_option(options)
24
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
25
47
  alias_method_chain :rewrite, :secure_option
26
48
  end
27
49
  end
@@ -1,20 +1,20 @@
1
1
  Gem::Specification.new do |s|
2
2
  s.name = 'ssl_requirement'
3
- s.version = '1.0.4'
4
- s.date = '2008-07-04'
3
+ s.version = '1.0.6'
4
+ s.date = '2009-06-22'
5
5
 
6
6
  s.summary = "Allow controller actions to force SSL on specific parts of the site."
7
7
  s.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."
8
8
 
9
- s.authors = ['RailsJedi', 'David Heinemeier Hansson']
10
- s.email = 'railsjedi@gmail.com'
11
- s.homepage = 'http://github.com/jcnetdev/ssl_requirement'
9
+ s.authors = ['RailsJedi', 'David Heinemeier Hansson', 'jcnetdev', 'bcurren', 'bmpercy']
10
+ s.email = 'percival@umamibud.com'
11
+ s.homepage = 'http://github.com/bmpercy/ssl_requirement'
12
12
 
13
13
  s.has_rdoc = true
14
14
  s.rdoc_options = ["--main", "README"]
15
15
  s.extra_rdoc_files = ["README"]
16
16
 
17
- s.add_dependency 'rails', ['>= 2.1']
17
+ s.add_dependency 'rails', ['>= 2.3.2']
18
18
 
19
19
  s.files = ["README",
20
20
  "init.rb",
@@ -23,5 +23,6 @@ Gem::Specification.new do |s|
23
23
  "rails/init.rb",
24
24
  "ssl_requirement.gemspec"]
25
25
 
26
- s.test_files = ["test/ssl_requirement_test.rb"]
26
+ s.test_files = ["test/ssl_requirement_test.rb",
27
+ "test/url_rewriter_test.rb"]
27
28
  end
@@ -26,6 +26,12 @@ require "#{File.dirname(__FILE__)}/../lib/ssl_requirement"
26
26
  ActionController::Base.logger = nil
27
27
  ActionController::Routing::Routes.reload rescue nil
28
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
+
29
35
  class SslRequirementController < ActionController::Base
30
36
  include SslRequirement
31
37
 
@@ -33,21 +39,25 @@ class SslRequirementController < ActionController::Base
33
39
  ssl_allowed :c
34
40
 
35
41
  def a
42
+ flash[:abar] = "foo"
36
43
  render :nothing => true
37
44
  end
38
45
 
39
46
  def b
47
+ flash[:bbar] = "foo"
40
48
  render :nothing => true
41
49
  end
42
50
 
43
51
  def c
52
+ flash[:cbar] = "foo"
44
53
  render :nothing => true
45
54
  end
46
55
 
47
56
  def d
57
+ flash[:dbar] = "foo"
48
58
  render :nothing => true
49
59
  end
50
-
60
+
51
61
  def set_flash
52
62
  flash[:foo] = "bar"
53
63
  end
@@ -76,9 +86,6 @@ class SslExceptionController < ActionController::Base
76
86
  render :nothing => true
77
87
  end
78
88
 
79
- def set_flash
80
- flash[:foo] = "bar"
81
- end
82
89
  end
83
90
 
84
91
  class SslAllActionsController < ActionController::Base
@@ -92,42 +99,74 @@ class SslAllActionsController < ActionController::Base
92
99
 
93
100
  end
94
101
 
95
- class SslRequirementTest < Test::Unit::TestCase
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
96
121
  def setup
97
122
  @controller = SslRequirementController.new
98
- @request = ActionController::TestRequest.new
99
- @response = ActionController::TestResponse.new
123
+ @ssl_host_override = 'www.example.com:80443'
124
+ @non_ssl_host_override = 'www.example.com:8080'
100
125
  end
126
+
127
+ # flash-related tests
101
128
 
102
129
  def test_redirect_to_https_preserves_flash
130
+ assert_not_equal "on", @request.env["HTTPS"]
103
131
  get :set_flash
104
132
  get :b
105
- assert_response :redirect
106
- assert_equal "bar", flash[:foo]
133
+ assert_response :redirect # check redirect happens (flash still set)
134
+ get :b # get again to flush flash
135
+ assert_response :redirect # make sure it happens again
136
+ assert_equal "bar", flash[:foo] # the flash would be gone now if no redirect
107
137
  end
108
138
 
109
139
  def test_not_redirecting_to_https_does_not_preserve_the_flash
140
+ assert_not_equal "on", @request.env["HTTPS"]
110
141
  get :set_flash
111
142
  get :d
112
- assert_response :success
113
- assert_nil flash[:foo]
143
+ assert_response :success # check no redirect (flash still set)
144
+ get :d # get again to flush flash
145
+ assert_response :success # check no redirect
146
+ assert_nil flash[:foo] # the flash should be gone now
114
147
  end
115
148
 
116
149
  def test_redirect_to_http_preserves_flash
117
150
  get :set_flash
118
151
  @request.env['HTTPS'] = "on"
119
152
  get :d
120
- assert_response :redirect
121
- assert_equal "bar", flash[:foo]
153
+ assert_response :redirect # check redirect happens (flash still set)
154
+ get :d # get again to flush flash
155
+ assert_response :redirect # make sure redirect happens
156
+ assert_equal "bar", flash[:foo] # flash would be gone now if no redirect
122
157
  end
123
158
 
124
159
  def test_not_redirecting_to_http_does_not_preserve_the_flash
125
160
  get :set_flash
126
161
  @request.env['HTTPS'] = "on"
127
162
  get :a
128
- assert_response :success
129
- assert_nil flash[:foo]
163
+ assert_response :success # no redirect (flash still set)
164
+ get :a # get again to flush flash
165
+ assert_response :success # no redirect
166
+ assert_nil flash[:foo] # flash should be gone now
130
167
  end
168
+
169
+ # ssl required/allowed/exceptions testing
131
170
 
132
171
  def test_required_without_ssl
133
172
  assert_not_equal "on", @request.env["HTTPS"]
@@ -155,13 +194,12 @@ class SslRequirementTest < Test::Unit::TestCase
155
194
 
156
195
  def test_ssl_exceptions_without_ssl
157
196
  @controller = SslExceptionController.new
197
+ assert_not_equal "on", @request.env["HTTPS"]
158
198
  get :a
159
199
  assert_response :redirect
160
200
  assert_match %r{^https://}, @response.headers['Location']
161
-
162
201
  get :b
163
202
  assert_response :success
164
-
165
203
  get :c # c is not explicity in ssl_required, but it is not listed in ssl_exceptions
166
204
  assert_response :redirect
167
205
  assert_match %r{^https://}, @response.headers['Location']
@@ -172,8 +210,6 @@ class SslRequirementTest < Test::Unit::TestCase
172
210
  @request.env['HTTPS'] = "on"
173
211
  get :a
174
212
  assert_response :success
175
-
176
- @request.env['HTTPS'] = "on"
177
213
  get :c
178
214
  assert_response :success
179
215
  end
@@ -181,7 +217,6 @@ class SslRequirementTest < Test::Unit::TestCase
181
217
  def test_ssl_all_actions_without_ssl
182
218
  @controller = SslAllActionsController.new
183
219
  get :a
184
-
185
220
  assert_response :redirect
186
221
  assert_match %r{^https://}, @response.headers['Location']
187
222
  end
@@ -216,5 +251,50 @@ class SslRequirementTest < Test::Unit::TestCase
216
251
  ensure
217
252
  SslRequirement.disable_ssl_check = false
218
253
  end
219
-
220
- end
254
+
255
+ # testing overriding hostnames for ssl, non-ssl
256
+
257
+ # test for overriding (or not) the ssl_host and non_ssl_host variables
258
+ # using actions a (ssl required) and d (ssl not required or allowed)
259
+
260
+ def test_ssl_redirect_with_ssl_host
261
+ SslRequirement.ssl_host = @ssl_host_override
262
+ assert_not_equal "on", @request.env["HTTPS"]
263
+ get :a
264
+ assert_response :redirect
265
+ assert_match Regexp.new("^https://#{@ssl_host_override}"),
266
+ @response.headers['Location']
267
+ SslRequirement.ssl_host = nil
268
+ end
269
+
270
+ def test_ssl_redirect_without_ssl_host
271
+ SslRequirement.ssl_host = nil
272
+ assert_not_equal "on", @request.env["HTTPS"]
273
+ get :a
274
+ assert_response :redirect
275
+ assert_match Regexp.new("^https://"), @response.headers['Location']
276
+ assert_no_match Regexp.new("^https://#{@ssl_host_override}"),
277
+ @response.headers['Location']
278
+ end
279
+
280
+ def test_non_ssl_redirect_with_non_ssl_host
281
+ SslRequirement.non_ssl_host = @non_ssl_host_override
282
+ @request.env['HTTPS'] = 'on'
283
+ get :d
284
+ assert_response :redirect
285
+ assert_match Regexp.new("^http://#{@non_ssl_host_override}"),
286
+ @response.headers['Location']
287
+ SslRequirement.non_ssl_host = nil
288
+ end
289
+
290
+ def test_non_ssl_redirect_without_non_ssl_host
291
+ SslRequirement.non_ssl_host = nil
292
+ @request.env['HTTPS'] = 'on'
293
+ get :d
294
+ assert_response :redirect
295
+ assert_match Regexp.new("^http://"), @response.headers['Location']
296
+ assert_no_match Regexp.new("^http://#{@non_ssl_host_override}"),
297
+ @response.headers['Location']
298
+ end
299
+
300
+ end
@@ -0,0 +1,142 @@
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
+ end
metadata CHANGED
@@ -1,16 +1,19 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: bcurren-ssl_requirement
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.0.4
4
+ version: 1.0.6
5
5
  platform: ruby
6
6
  authors:
7
7
  - RailsJedi
8
8
  - David Heinemeier Hansson
9
+ - jcnetdev
10
+ - bcurren
11
+ - bmpercy
9
12
  autorequire:
10
13
  bindir: bin
11
14
  cert_chain: []
12
15
 
13
- date: 2008-07-04 00:00:00 -07:00
16
+ date: 2009-06-22 00:00:00 -07:00
14
17
  default_executable:
15
18
  dependencies:
16
19
  - !ruby/object:Gem::Dependency
@@ -21,10 +24,10 @@ dependencies:
21
24
  requirements:
22
25
  - - ">="
23
26
  - !ruby/object:Gem::Version
24
- version: "2.1"
27
+ version: 2.3.2
25
28
  version:
26
29
  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.
27
- email: railsjedi@gmail.com
30
+ email: percival@umamibud.com
28
31
  executables: []
29
32
 
30
33
  extensions: []
@@ -39,7 +42,7 @@ files:
39
42
  - rails/init.rb
40
43
  - ssl_requirement.gemspec
41
44
  has_rdoc: true
42
- homepage: http://github.com/jcnetdev/ssl_requirement
45
+ homepage: http://github.com/bmpercy/ssl_requirement
43
46
  post_install_message:
44
47
  rdoc_options:
45
48
  - --main
@@ -67,3 +70,4 @@ specification_version: 2
67
70
  summary: Allow controller actions to force SSL on specific parts of the site.
68
71
  test_files:
69
72
  - test/ssl_requirement_test.rb
73
+ - test/url_rewriter_test.rb