jscharf-ssl_requirement 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/README ADDED
@@ -0,0 +1,89 @@
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
+ You are able to turn disable ssl redirects by adding the following environment configuration file:
52
+ SslRequirement.disable_ssl_check = true
53
+
54
+ P.S.: Beware when you include the SslRequirement module. At the time of
55
+ inclusion, it'll add the before_filter that validates the declarations. Some
56
+ times you'll want to run other before_filters before that. They should then be
57
+ declared ahead of including this module.
58
+
59
+ SSL URL Helper
60
+ ==============
61
+ This plugin also adds a helper a :secure option to url_for and named_routes. This property
62
+ 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.
64
+
65
+ Here is an example of creating a secure url:
66
+
67
+ <%= url_for(:controller => "c", :action => "a", :secure => true) %>
68
+
69
+ If disable_ssl_check returns false url_for will return the following:
70
+
71
+ https://yoursite.com/c/a
72
+
73
+ Furthermore, you can use the secure option in a named route to create a secure form as follows:
74
+
75
+ <% form_tag session_path(:secure => true), :class => 'home_login' do -%>
76
+ <p>
77
+ <label for="name">Email</label>
78
+ <%= text_field_tag 'email', '', :class => 'text', :tabindex => 1 %>
79
+ </p>
80
+ <p>
81
+ <label for="password">Password</label>
82
+ <%= password_field_tag 'password', '', :class => 'text', :tabindex => 2 %>
83
+ </p>
84
+ <p>
85
+ <%= submit_tag "Login", :id => 'login_submit', :value => "", :alt => "Login" %>
86
+ </p>
87
+ <% end -%>
88
+
89
+ Copyright (c) 2005 David Heinemeier Hansson, released under the MIT license
data/VERSION.yml ADDED
@@ -0,0 +1,4 @@
1
+ ---
2
+ patch: 1
3
+ major: 1
4
+ minor: 1
@@ -0,0 +1,90 @@
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_reader :ssl_host
25
+
26
+ def self.ssl_host=(host)
27
+ @@ssl_host = host
28
+ end
29
+
30
+ def self.disable_ssl_check?
31
+ @@disable_ssl_check ||= false
32
+ end
33
+
34
+ def self.disable_ssl_check=(value)
35
+ @@disable_ssl_check = value
36
+ end
37
+
38
+ module ClassMethods
39
+ # Specifies that the named actions requires an SSL connection to be performed (which is enforced by ensure_proper_protocol).
40
+ def ssl_required(*actions)
41
+ write_inheritable_array(:ssl_required_actions, actions)
42
+ end
43
+
44
+ def ssl_exceptions(*actions)
45
+ write_inheritable_array(:ssl_required_except_actions, actions)
46
+ end
47
+
48
+ def ssl_allowed(*actions)
49
+ write_inheritable_array(:ssl_allowed_actions, actions)
50
+ end
51
+ end
52
+
53
+ protected
54
+ # Returns true if the current action is supposed to run as SSL
55
+ def ssl_required?
56
+ required = (self.class.read_inheritable_attribute(:ssl_required_actions) || [])
57
+ except = self.class.read_inheritable_attribute(:ssl_required_except_actions)
58
+
59
+ unless except
60
+ required.include?(action_name.to_sym)
61
+ else
62
+ !except.include?(action_name.to_sym)
63
+ end
64
+ end
65
+
66
+ def ssl_allowed?
67
+ (self.class.read_inheritable_attribute(:ssl_allowed_actions) || []).include?(action_name.to_sym)
68
+ end
69
+
70
+ private
71
+ def self.included(controller)
72
+ controller.extend(ClassMethods)
73
+ controller.before_filter(:ensure_proper_protocol)
74
+ end
75
+
76
+ def ensure_proper_protocol
77
+ return true if SslRequirement.disable_ssl_check?
78
+ return true if ssl_allowed?
79
+
80
+ if ssl_required? && !request.ssl?
81
+ redirect_to "https://" + (ssl_host || request.host) + request.request_uri
82
+ flash.keep
83
+ return false
84
+ elsif request.ssl? && !ssl_required?
85
+ redirect_to "http://" + request.host + request.request_uri
86
+ flash.keep
87
+ return false
88
+ end
89
+ end
90
+ end
@@ -0,0 +1,25 @@
1
+ require 'action_controller/url_rewriter'
2
+ require 'action_controller/routing/optimisations'
3
+
4
+ module ActionController
5
+ class UrlRewriter
6
+ # Add a secure option to the rewrite method.
7
+ def rewrite_with_secure_option(options = {})
8
+ secure = options.delete(:secure)
9
+ options.merge!(:only_path => false, :protocol => secure ? 'https' : 'http') unless SslRequirement.disable_ssl_check?
10
+ rewrite_without_secure_option options
11
+ end
12
+ alias_method_chain :rewrite, :secure_option
13
+ end
14
+
15
+ module Routing
16
+ module Optimisation
17
+ class PositionalArgumentsWithAdditionalParams
18
+ def guard_conditions_with_secure_option
19
+ guard_conditions_without_secure_option + ['!args.last.has_key?(:secure)']
20
+ end
21
+ alias_method_chain :guard_conditions, :secure_option
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,220 @@
1
+ require 'set'
2
+ require 'rubygems'
3
+ require 'activesupport'
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
+ class SslRequirementController < ActionController::Base
30
+ include SslRequirement
31
+
32
+ ssl_required :a, :b
33
+ ssl_allowed :c
34
+
35
+ def a
36
+ render :nothing => true
37
+ end
38
+
39
+ def b
40
+ render :nothing => true
41
+ end
42
+
43
+ def c
44
+ render :nothing => true
45
+ end
46
+
47
+ def d
48
+ render :nothing => true
49
+ end
50
+
51
+ def set_flash
52
+ flash[:foo] = "bar"
53
+ end
54
+ end
55
+
56
+ class SslExceptionController < ActionController::Base
57
+ include SslRequirement
58
+
59
+ ssl_required :a
60
+ ssl_exceptions :b
61
+ ssl_allowed :d
62
+
63
+ def a
64
+ render :nothing => true
65
+ end
66
+
67
+ def b
68
+ render :nothing => true
69
+ end
70
+
71
+ def c
72
+ render :nothing => true
73
+ end
74
+
75
+ def d
76
+ render :nothing => true
77
+ end
78
+
79
+ def set_flash
80
+ flash[:foo] = "bar"
81
+ end
82
+ end
83
+
84
+ class SslAllActionsController < ActionController::Base
85
+ include SslRequirement
86
+
87
+ ssl_exceptions
88
+
89
+ def a
90
+ render :nothing => true
91
+ end
92
+
93
+ end
94
+
95
+ class SslRequirementTest < Test::Unit::TestCase
96
+ def setup
97
+ @controller = SslRequirementController.new
98
+ @request = ActionController::TestRequest.new
99
+ @response = ActionController::TestResponse.new
100
+ end
101
+
102
+ def test_redirect_to_https_preserves_flash
103
+ get :set_flash
104
+ get :b
105
+ assert_response :redirect
106
+ assert_equal "bar", flash[:foo]
107
+ end
108
+
109
+ def test_not_redirecting_to_https_does_not_preserve_the_flash
110
+ get :set_flash
111
+ get :d
112
+ assert_response :success
113
+ assert_nil flash[:foo]
114
+ end
115
+
116
+ def test_redirect_to_http_preserves_flash
117
+ get :set_flash
118
+ @request.env['HTTPS'] = "on"
119
+ get :d
120
+ assert_response :redirect
121
+ assert_equal "bar", flash[:foo]
122
+ end
123
+
124
+ def test_not_redirecting_to_http_does_not_preserve_the_flash
125
+ get :set_flash
126
+ @request.env['HTTPS'] = "on"
127
+ get :a
128
+ assert_response :success
129
+ assert_nil flash[:foo]
130
+ end
131
+
132
+ def test_required_without_ssl
133
+ assert_not_equal "on", @request.env["HTTPS"]
134
+ get :a
135
+ assert_response :redirect
136
+ assert_match %r{^https://}, @response.headers['Location']
137
+ get :b
138
+ assert_response :redirect
139
+ assert_match %r{^https://}, @response.headers['Location']
140
+ end
141
+
142
+ def test_required_with_ssl
143
+ @request.env['HTTPS'] = "on"
144
+ get :a
145
+ assert_response :success
146
+ get :b
147
+ assert_response :success
148
+ end
149
+
150
+ def test_disallowed_without_ssl
151
+ assert_not_equal "on", @request.env["HTTPS"]
152
+ get :d
153
+ assert_response :success
154
+ end
155
+
156
+ def test_ssl_exceptions_without_ssl
157
+ @controller = SslExceptionController.new
158
+ get :a
159
+ assert_response :redirect
160
+ assert_match %r{^https://}, @response.headers['Location']
161
+
162
+ get :b
163
+ assert_response :success
164
+
165
+ get :c # c is not explicity in ssl_required, but it is not listed in ssl_exceptions
166
+ assert_response :redirect
167
+ assert_match %r{^https://}, @response.headers['Location']
168
+ end
169
+
170
+ def test_ssl_exceptions_with_ssl
171
+ @controller = SslExceptionController.new
172
+ @request.env['HTTPS'] = "on"
173
+ get :a
174
+ assert_response :success
175
+
176
+ @request.env['HTTPS'] = "on"
177
+ get :c
178
+ assert_response :success
179
+ end
180
+
181
+ def test_ssl_all_actions_without_ssl
182
+ @controller = SslAllActionsController.new
183
+ get :a
184
+
185
+ assert_response :redirect
186
+ assert_match %r{^https://}, @response.headers['Location']
187
+ end
188
+
189
+ def test_disallowed_with_ssl
190
+ @request.env['HTTPS'] = "on"
191
+ get :d
192
+ assert_response :redirect
193
+ assert_match %r{^http://}, @response.headers['Location']
194
+ end
195
+
196
+ def test_allowed_without_ssl
197
+ assert_not_equal "on", @request.env["HTTPS"]
198
+ get :c
199
+ assert_response :success
200
+ end
201
+
202
+ def test_allowed_with_ssl
203
+ @request.env['HTTPS'] = "on"
204
+ get :c
205
+ assert_response :success
206
+ end
207
+
208
+ def test_disable_ssl_check
209
+ SslRequirement.disable_ssl_check = true
210
+
211
+ assert_not_equal "on", @request.env["HTTPS"]
212
+ get :a
213
+ assert_response :success
214
+ get :b
215
+ assert_response :success
216
+ ensure
217
+ SslRequirement.disable_ssl_check = false
218
+ end
219
+
220
+ end
@@ -0,0 +1,77 @@
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
+ puts @url_rewriter.to_s
22
+ end
23
+
24
+ def test_rewrite_secure_false
25
+ SslRequirement.disable_ssl_check = false
26
+ assert_equal('http://test.host/c/a',
27
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :secure => false)
28
+ )
29
+ assert_equal('http://test.host/c/a',
30
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :secure => false, :only_path => true)
31
+ )
32
+
33
+ SslRequirement.disable_ssl_check = true
34
+ assert_equal('http://test.host/c/a',
35
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :secure => false)
36
+ )
37
+ assert_equal('/c/a',
38
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :secure => false, :only_path => true)
39
+ )
40
+ end
41
+
42
+ def test_rewrite_secure_true
43
+ SslRequirement.disable_ssl_check = false
44
+ assert_equal('https://test.host/c/a',
45
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :secure => true)
46
+ )
47
+ assert_equal('https://test.host/c/a',
48
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :secure => true, :only_path => true)
49
+ )
50
+
51
+ SslRequirement.disable_ssl_check = true
52
+ assert_equal('http://test.host/c/a',
53
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :secure => true)
54
+ )
55
+ assert_equal('/c/a',
56
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :secure => true, :only_path => true)
57
+ )
58
+ end
59
+
60
+ def test_rewrite_secure_not_specified
61
+ SslRequirement.disable_ssl_check = false
62
+ assert_equal('http://test.host/c/a',
63
+ @rewriter.rewrite(:controller => 'c', :action => 'a')
64
+ )
65
+ assert_equal('/c/a',
66
+ @rewriter.rewrite(:controller => 'c', :action => 'a', :only_path => true)
67
+ )
68
+
69
+ SslRequirement.disable_ssl_check = true
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
+ end
77
+ end
metadata ADDED
@@ -0,0 +1,69 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: jscharf-ssl_requirement
3
+ version: !ruby/object:Gem::Version
4
+ version: 1.1.1
5
+ platform: ruby
6
+ authors:
7
+ - RailsJedi
8
+ - David Heinemeier Hansson
9
+ autorequire:
10
+ bindir: bin
11
+ cert_chain: []
12
+
13
+ date: 2009-02-19 00:00:00 -08:00
14
+ default_executable:
15
+ dependencies:
16
+ - !ruby/object:Gem::Dependency
17
+ name: rails
18
+ type: :runtime
19
+ version_requirement:
20
+ version_requirements: !ruby/object:Gem::Requirement
21
+ requirements:
22
+ - - ">="
23
+ - !ruby/object:Gem::Version
24
+ version: "2.1"
25
+ version:
26
+ 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
28
+ executables: []
29
+
30
+ extensions: []
31
+
32
+ extra_rdoc_files:
33
+ - README
34
+ files:
35
+ - VERSION.yml
36
+ - lib/ssl_requirement.rb
37
+ - lib/url_rewriter.rb
38
+ - test/ssl_requirement_test.rb
39
+ - test/url_rewriter_test.rb
40
+ - README
41
+ has_rdoc: true
42
+ homepage: http://github.com/tbmcmullen/ssl_requirement
43
+ post_install_message:
44
+ rdoc_options:
45
+ - --main
46
+ - README
47
+ require_paths:
48
+ - lib
49
+ required_ruby_version: !ruby/object:Gem::Requirement
50
+ requirements:
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: "0"
54
+ version:
55
+ required_rubygems_version: !ruby/object:Gem::Requirement
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ version: "0"
60
+ version:
61
+ requirements: []
62
+
63
+ rubyforge_project:
64
+ rubygems_version: 1.2.0
65
+ signing_key:
66
+ specification_version: 2
67
+ summary: Allow controller actions to force SSL on specific parts of the site.
68
+ test_files: []
69
+