bcurren-ssl_requirement 1.0.4 → 1.0.6

Sign up to get free protection for your applications and to get access to all the features.
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