clearance 1.10.1 → 1.17.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of clearance might be problematic. Click here for more details.

Files changed (106) hide show
  1. checksums.yaml +5 -5
  2. data/.gitignore +1 -0
  3. data/.travis.yml +20 -8
  4. data/.yardopts +3 -0
  5. data/Appraisals +13 -16
  6. data/Gemfile +7 -5
  7. data/Gemfile.lock +124 -130
  8. data/NEWS.md +171 -2
  9. data/README.md +99 -42
  10. data/app/controllers/clearance/passwords_controller.rb +35 -21
  11. data/app/controllers/clearance/sessions_controller.rb +17 -3
  12. data/app/controllers/clearance/users_controller.rb +10 -4
  13. data/app/mailers/clearance_mailer.rb +2 -3
  14. data/app/views/clearance_mailer/change_password.text.erb +1 -1
  15. data/app/views/layouts/application.html.erb +0 -1
  16. data/bin/setup +6 -2
  17. data/clearance.gemspec +5 -2
  18. data/config/locales/clearance.en.yml +9 -0
  19. data/gemfiles/rails_4.2.gemfile +20 -0
  20. data/gemfiles/rails_5.0.gemfile +21 -0
  21. data/gemfiles/rails_5.1.gemfile +21 -0
  22. data/gemfiles/rails_5.2.gemfile +21 -0
  23. data/lib/clearance/authentication.rb +63 -3
  24. data/lib/clearance/authorization.rb +48 -5
  25. data/lib/clearance/back_door.rb +55 -6
  26. data/lib/clearance/configuration.rb +50 -10
  27. data/lib/clearance/constraints/signed_in.rb +21 -0
  28. data/lib/clearance/constraints/signed_out.rb +12 -0
  29. data/lib/clearance/constraints.rb +12 -0
  30. data/lib/clearance/controller.rb +13 -0
  31. data/lib/clearance/default_sign_in_guard.rb +17 -0
  32. data/lib/clearance/engine.rb +18 -5
  33. data/lib/clearance/password_strategies/bcrypt.rb +16 -21
  34. data/lib/clearance/password_strategies/bcrypt_migration_from_sha1.rb +10 -0
  35. data/lib/clearance/password_strategies/blowfish.rb +10 -1
  36. data/lib/clearance/password_strategies/sha1.rb +9 -0
  37. data/lib/clearance/password_strategies.rb +13 -0
  38. data/lib/clearance/rack_session.rb +13 -0
  39. data/lib/clearance/rspec.rb +15 -4
  40. data/lib/clearance/session.rb +62 -13
  41. data/lib/clearance/session_status.rb +7 -0
  42. data/lib/clearance/sign_in_guard.rb +65 -0
  43. data/lib/clearance/test_unit.rb +3 -3
  44. data/lib/clearance/testing/controller_helpers.rb +57 -0
  45. data/lib/clearance/testing/deny_access_matcher.rb +36 -2
  46. data/lib/clearance/testing/helpers.rb +9 -25
  47. data/lib/clearance/testing/view_helpers.rb +32 -0
  48. data/lib/clearance/token.rb +7 -0
  49. data/lib/clearance/user.rb +183 -4
  50. data/lib/clearance/version.rb +1 -1
  51. data/lib/generators/clearance/install/install_generator.rb +28 -9
  52. data/lib/generators/clearance/install/templates/README +1 -1
  53. data/lib/generators/clearance/install/templates/clearance.rb +1 -0
  54. data/lib/generators/clearance/install/templates/db/migrate/{add_clearance_to_users.rb → add_clearance_to_users.rb.erb} +3 -3
  55. data/lib/generators/clearance/install/templates/db/migrate/{create_users.rb → create_users.rb.erb} +2 -2
  56. data/lib/generators/clearance/install/templates/user.rb.erb +3 -0
  57. data/lib/generators/clearance/routes/routes_generator.rb +23 -0
  58. data/lib/generators/clearance/routes/templates/routes.rb +7 -7
  59. data/lib/generators/clearance/specs/templates/factories/clearance.rb +2 -2
  60. data/lib/generators/clearance/specs/templates/features/clearance/user_signs_out_spec.rb.tt +1 -1
  61. data/lib/generators/clearance/specs/templates/features/clearance/visitor_resets_password_spec.rb.tt +12 -3
  62. data/lib/generators/clearance/specs/templates/features/clearance/visitor_signs_in_spec.rb.tt +3 -3
  63. data/lib/generators/clearance/specs/templates/features/clearance/visitor_signs_up_spec.rb.tt +1 -1
  64. data/lib/generators/clearance/specs/templates/features/clearance/visitor_updates_password_spec.rb.tt +2 -2
  65. data/lib/generators/clearance/specs/templates/support/features/clearance_helpers.rb +2 -2
  66. data/spec/acceptance/clearance_installation_spec.rb +15 -7
  67. data/spec/app_templates/app/models/rails5/user.rb +5 -0
  68. data/spec/app_templates/config/initializers/clearance.rb +2 -0
  69. data/spec/app_templates/testapp/Gemfile +1 -1
  70. data/spec/app_templates/testapp/app/controllers/home_controller.rb +5 -1
  71. data/spec/clearance/back_door_spec.rb +70 -6
  72. data/spec/clearance/session_spec.rb +4 -16
  73. data/spec/clearance/testing/controller_helpers_spec.rb +38 -0
  74. data/spec/clearance/testing/view_helpers_spec.rb +37 -0
  75. data/spec/configuration_spec.rb +79 -86
  76. data/spec/controllers/apis_controller_spec.rb +6 -2
  77. data/spec/controllers/forgeries_controller_spec.rb +12 -3
  78. data/spec/controllers/passwords_controller_spec.rb +74 -38
  79. data/spec/controllers/permissions_controller_spec.rb +13 -3
  80. data/spec/controllers/sessions_controller_spec.rb +40 -11
  81. data/spec/controllers/users_controller_spec.rb +16 -8
  82. data/spec/dummy/app/controllers/application_controller.rb +5 -1
  83. data/spec/dummy/application.rb +9 -11
  84. data/spec/factories.rb +5 -5
  85. data/spec/generators/clearance/install/install_generator_spec.rb +29 -3
  86. data/spec/generators/clearance/routes/routes_generator_spec.rb +5 -1
  87. data/spec/helpers/helper_helpers_spec.rb +10 -0
  88. data/spec/{user_spec.rb → models/user_spec.rb} +10 -1
  89. data/spec/password_strategies/blowfish_spec.rb +1 -1
  90. data/spec/requests/cookie_options_spec.rb +52 -0
  91. data/spec/requests/csrf_rotation_spec.rb +35 -0
  92. data/spec/requests/password_maintenance_spec.rb +18 -0
  93. data/spec/requests/token_expiration_spec.rb +54 -0
  94. data/spec/spec_helper.rb +22 -4
  95. data/spec/support/environment.rb +12 -0
  96. data/spec/support/generator_spec_helpers.rb +13 -1
  97. data/spec/support/http_method_shim.rb +25 -0
  98. data/spec/support/request_with_remember_token.rb +5 -0
  99. data/spec/views/view_helpers_spec.rb +10 -0
  100. metadata +69 -15
  101. data/gemfiles/rails3.2.gemfile +0 -18
  102. data/gemfiles/rails4.0.gemfile +0 -19
  103. data/gemfiles/rails4.1.gemfile +0 -18
  104. data/gemfiles/rails4.2.gemfile +0 -18
  105. data/lib/generators/clearance/install/templates/user.rb +0 -3
  106. data/spec/clearance/testing/helpers_spec.rb +0 -38
@@ -3,8 +3,11 @@ module Clearance
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- helper_method :current_user, :signed_in?, :signed_out?
7
- hide_action(
6
+ if respond_to?(:helper_method)
7
+ helper_method :current_user, :signed_in?, :signed_out?
8
+ end
9
+
10
+ private(
8
11
  :authenticate,
9
12
  :current_user,
10
13
  :current_user=,
@@ -16,40 +19,96 @@ module Clearance
16
19
  )
17
20
  end
18
21
 
22
+ # Authenticate a user with a provided email and password
23
+ # @param [ActionController::Parameters] params The parameters from the
24
+ # sign in form. `params[:session][:email]` and
25
+ # `params[:session][:password]` are required.
26
+ # @return [User, nil] The user or nil if authentication fails.
19
27
  def authenticate(params)
20
28
  Clearance.configuration.user_model.authenticate(
21
29
  params[:session][:email], params[:session][:password]
22
30
  )
23
31
  end
24
32
 
33
+ # Get the user from the current clearance session. Exposed as a
34
+ # `helper_method`, making it visible to views. Prefer {#signed_in?} or
35
+ # {#signed_out?} if you only want to check for the presence of a current
36
+ # user rather than access the actual user.
37
+ #
38
+ # @return [User, nil] The user if one is signed in or nil otherwise.
25
39
  def current_user
26
40
  clearance_session.current_user
27
41
  end
28
42
 
43
+ # @deprecated Use the {#sign_in} method instead.
29
44
  def current_user=(user)
30
45
  warn "#{Kernel.caller.first}: [DEPRECATION] " +
31
46
  'Assigning the current_user has been deprecated. Use the sign_in method instead.'
32
47
  clearance_session.sign_in user
33
48
  end
34
49
 
50
+ # Sign in the provided user.
51
+ # @param [User] user
52
+ #
53
+ # Signing in will run the stack of {Configuration#sign_in_guards}.
54
+ #
55
+ # You can provide a block to this method to handle the result of that stack.
56
+ # Your block will receive either a {SuccessStatus} or {FailureStatus}
57
+ #
58
+ # sign_in(user) do |status|
59
+ # if status.success?
60
+ # # ...
61
+ # else
62
+ # # ...
63
+ # end
64
+ # end
65
+ #
66
+ # For an example of how clearance uses this internally, see
67
+ # {SessionsController#create}.
68
+ #
69
+ # Signing in will also regenerate the CSRF token for the current session,
70
+ # provided {Configuration#rotate_csrf_token_on_sign_in} is set.
35
71
  def sign_in(user, &block)
36
- clearance_session.sign_in user, &block
72
+ clearance_session.sign_in(user, &block)
73
+
74
+ if signed_in? && Clearance.configuration.rotate_csrf_on_sign_in?
75
+ session.delete(:_csrf_token)
76
+ form_authenticity_token
77
+ end
37
78
  end
38
79
 
80
+ # Destroy the current user's Clearance session.
81
+ # See {Session#sign_out} for specifics.
39
82
  def sign_out
40
83
  clearance_session.sign_out
41
84
  end
42
85
 
86
+ # True if there is a currently-signed-in user. Exposed as a `helper_method`,
87
+ # making it available to views.
88
+ #
89
+ # Using `signed_in?` is preferable to checking {#current_user} against nil
90
+ # as it will allow you to introduce a null user object more simply at a
91
+ # later date.
92
+ #
93
+ # @return [Boolean]
43
94
  def signed_in?
44
95
  clearance_session.signed_in?
45
96
  end
46
97
 
98
+ # True if there is no currently-signed-in user. Exposed as a
99
+ # `helper_method`, making it available to views.
100
+ #
101
+ # Usings `signed_out?` is preferable to checking for presence of
102
+ # {#current_user} as it will allow you to introduce a null user object more
103
+ # simply at a later date.
47
104
  def signed_out?
48
105
  !signed_in?
49
106
  end
50
107
 
51
108
  # CSRF protection in Rails >= 3.0.4
109
+ #
52
110
  # http://weblog.rubyonrails.org/2011/2/8/csrf-protection-bypass-in-ruby-on-rails
111
+ # @private
53
112
  def handle_unverified_request
54
113
  super
55
114
  sign_out
@@ -57,6 +116,7 @@ module Clearance
57
116
 
58
117
  protected
59
118
 
119
+ # @api private
60
120
  def clearance_session
61
121
  request.env[:clearance]
62
122
  end
@@ -3,23 +3,52 @@ module Clearance
3
3
  extend ActiveSupport::Concern
4
4
 
5
5
  included do
6
- hide_action :authorize, :deny_access, :require_login
6
+ private :authorize, :deny_access, :require_login
7
7
  end
8
8
 
9
+ # Use as a `before_action` to require a user be signed in to proceed.
10
+ # {Authentication#signed_in?} is used to determine if there is a signed in
11
+ # user or not.
12
+ #
13
+ # class PostsController < ApplicationController
14
+ # before_action :require_login
15
+ #
16
+ # def index
17
+ # # ...
18
+ # end
19
+ # end
9
20
  def require_login
10
21
  unless signed_in?
11
- deny_access
22
+ deny_access(I18n.t("flashes.failure_when_not_signed_in"))
12
23
  end
13
24
  end
14
25
 
26
+ # @deprecated use {#require_login}
15
27
  def authorize
16
- warn "[DEPRECATION] Clearance's `authorize` before_filter is " +
28
+ warn "[DEPRECATION] Clearance's `authorize` before_action is " +
17
29
  "deprecated. Use `require_login` instead. Be sure to update any " +
18
- "instances of `skip_before_filter :authorize` or " +
30
+ "instances of `skip_before_action :authorize` or " +
19
31
  "`skip_before_action :authorize` as well"
20
32
  require_login
21
33
  end
22
34
 
35
+ # Responds to unauthorized requests in a manner fitting the request format.
36
+ # `js`, `json`, and `xml` requests will receive a 401 with no body. All
37
+ # other formats will be redirected appropriately and can optionally have the
38
+ # flash message set.
39
+ #
40
+ # When redirecting, the originally requested url will be stored in the
41
+ # session (`session[:return_to]`), allowing it to be used as a redirect url
42
+ # once the user has successfully signed in.
43
+ #
44
+ # If there is a signed in user, the request will be redirected according to
45
+ # the value returned from {#url_after_denied_access_when_signed_in}.
46
+ #
47
+ # If there is no signed in user, the request will be redirected according to
48
+ # the value returned from {#url_after_denied_access_when_signed_out}.
49
+ # For the exact redirect behavior, see {#redirect_request}.
50
+ #
51
+ # @param [String] flash_message
23
52
  def deny_access(flash_message = nil)
24
53
  respond_to do |format|
25
54
  format.any(:js, :json, :xml) { head :unauthorized }
@@ -29,6 +58,7 @@ module Clearance
29
58
 
30
59
  protected
31
60
 
61
+ # @api private
32
62
  def redirect_request(flash_message)
33
63
  store_location
34
64
 
@@ -43,36 +73,49 @@ module Clearance
43
73
  end
44
74
  end
45
75
 
76
+ # @api private
46
77
  def clear_return_to
47
78
  session[:return_to] = nil
48
79
  end
49
80
 
81
+ # @api private
50
82
  def store_location
51
83
  if request.get?
52
84
  session[:return_to] = request.original_fullpath
53
85
  end
54
86
  end
55
87
 
88
+ # @api private
56
89
  def redirect_back_or(default)
57
90
  redirect_to(return_to || default)
58
91
  clear_return_to
59
92
  end
60
93
 
94
+ # @api private
61
95
  def return_to
62
96
  if return_to_url
63
97
  uri = URI.parse(return_to_url)
64
- "#{uri.path}?#{uri.query}".chomp('?')
98
+ "#{uri.path}?#{uri.query}".chomp("?") + "##{uri.fragment}".chomp("#")
65
99
  end
66
100
  end
67
101
 
102
+ # @api private
68
103
  def return_to_url
69
104
  session[:return_to]
70
105
  end
71
106
 
107
+ # Used as the redirect location when {#deny_access} is called and there is a
108
+ # currently signed in user.
109
+ #
110
+ # @return [String]
72
111
  def url_after_denied_access_when_signed_in
73
112
  Clearance.configuration.redirect_url
74
113
  end
75
114
 
115
+ # Used as the redirect location when {#deny_access} is called and there is
116
+ # no currently signed in user.
117
+ #
118
+ # @return [String]
76
119
  def url_after_denied_access_when_signed_out
77
120
  sign_in_url
78
121
  end
@@ -1,6 +1,7 @@
1
1
  module Clearance
2
2
  # Middleware which allows signing in by passing as=USER_ID in a query
3
- # parameter.
3
+ # parameter. If `User#to_param` is overriden you may pass a block to
4
+ # override the default user lookup behaviour
4
5
  #
5
6
  # Designed to eliminate time in integration tests wasted by visiting and
6
7
  # submitting the sign in form.
@@ -14,12 +15,28 @@ module Clearance
14
15
  # # ...
15
16
  # end
16
17
  #
18
+ # # or if `User#to_param` is overridden (to `username` for example):
19
+ #
20
+ # # config/environments/test.rb
21
+ # MyRailsApp::Application.configure do
22
+ # # ...
23
+ # config.middleware.use Clearance::BackDoor do |username|
24
+ # User.find_by(username: username)
25
+ # end
26
+ # # ...
27
+ # end
28
+ #
17
29
  # Usage:
18
30
  #
19
31
  # visit new_feedback_path(as: user)
20
32
  class BackDoor
21
- def initialize(app)
33
+ def initialize(app, &block)
34
+ unless environment_is_allowed?
35
+ raise error_message
36
+ end
37
+
22
38
  @app = app
39
+ @block = block
23
40
  end
24
41
 
25
42
  def call(env)
@@ -29,14 +46,46 @@ module Clearance
29
46
 
30
47
  private
31
48
 
49
+ # @api private
32
50
  def sign_in_through_the_back_door(env)
33
- params = Rack::Utils.parse_query(env['QUERY_STRING'])
34
- user_id = params['as']
51
+ params = Rack::Utils.parse_query(env["QUERY_STRING"])
52
+ user_param = params["as"]
35
53
 
36
- if user_id.present?
37
- user = Clearance.configuration.user_model.find(user_id)
54
+ if user_param.present?
55
+ user = find_user(user_param)
38
56
  env[:clearance].sign_in(user)
39
57
  end
40
58
  end
59
+
60
+ # @api private
61
+ def find_user(user_param)
62
+ if @block
63
+ @block.call(user_param)
64
+ else
65
+ Clearance.configuration.user_model.find(user_param)
66
+ end
67
+ end
68
+
69
+ # @api private
70
+ def environment_is_allowed?
71
+ allowed_environments.include? ENV["RAILS_ENV"]
72
+ end
73
+
74
+ # @api private
75
+ def allowed_environments
76
+ Clearance.configuration.allowed_backdoor_environments || []
77
+ end
78
+
79
+ # @api private
80
+ def error_message
81
+ unless allowed_environments.empty?
82
+ <<-EOS.squish
83
+ Can't use auth backdoor outside of
84
+ configured environments (#{allowed_environments.join(", ")}).
85
+ EOS
86
+ else
87
+ "BackDoor auth is disabled."
88
+ end
89
+ end
41
90
  end
42
91
  end
@@ -35,8 +35,8 @@ module Clearance
35
35
  # @return [String]
36
36
  attr_accessor :cookie_path
37
37
 
38
- # Controls whether the HttpOnly flag should be set on the remember token
39
- # cookie. Defaults to `false`. If `true`, the cookie will not be made
38
+ # Controls whether the HttpOnly flag should be set on the remember token
39
+ # cookie. Defaults to `true`, which prevents the cookie from being made
40
40
  # available to JavaScript. For more see
41
41
  # [RFC6265](http://tools.ietf.org/html/rfc6265#section-5.2.6).
42
42
  # @return [Boolean]
@@ -48,8 +48,8 @@ module Clearance
48
48
  attr_accessor :mailer_sender
49
49
 
50
50
  # The password strategy to use when authenticating and setting passwords.
51
- # Defaults to `Clearance::PasswordStrategies::BCrypt`.
52
- # @return [Class #authenticated? #password=]
51
+ # Defaults to {Clearance::PasswordStrategies::BCrypt}.
52
+ # @return [Module #authenticated? #password=]
53
53
  attr_accessor :password_strategy
54
54
 
55
55
  # The default path Clearance will redirect signed in users to.
@@ -58,6 +58,11 @@ module Clearance
58
58
  # @return [String]
59
59
  attr_accessor :redirect_url
60
60
 
61
+ # Controls whether Clearance will rotate the CSRF token on sign in.
62
+ # Defaults to `nil` which generates a warning. Will default to true in
63
+ # Clearance 2.0.
64
+ attr_accessor :rotate_csrf_on_sign_in
65
+
61
66
  # Set to `false` to disable Clearance's built-in routes.
62
67
  # Defaults to `true`. When set to false, your app is responsible for all
63
68
  # routes. You can dump a copy of Clearance's default routes with
@@ -81,19 +86,26 @@ module Clearance
81
86
  attr_accessor :sign_in_guards
82
87
 
83
88
  # The ActiveRecord class that represents users in your application.
84
- # Defualts to `::User`.
89
+ # Defaults to `::User`.
85
90
  # @return [ActiveRecord::Base]
86
91
  attr_accessor :user_model
87
92
 
93
+ # The array of allowed environments where `Clearance::BackDoor` is enabled.
94
+ # Defaults to ["test", "ci", "development"]
95
+ # @return [Array<String>]
96
+ attr_accessor :allowed_backdoor_environments
97
+
88
98
  def initialize
89
99
  @allow_sign_up = true
90
- @cookie_expiration = ->(cookies) { 1.year.from_now.utc }
100
+ @allowed_backdoor_environments = ["test", "ci", "development"]
91
101
  @cookie_domain = nil
92
- @cookie_path = '/'
102
+ @cookie_expiration = ->(cookies) { 1.year.from_now.utc }
93
103
  @cookie_name = "remember_token"
94
- @httponly = false
104
+ @cookie_path = '/'
105
+ @httponly = true
95
106
  @mailer_sender = 'reply@example.com'
96
107
  @redirect_url = '/'
108
+ @rotate_csrf_on_sign_in = nil
97
109
  @routes = true
98
110
  @secure_cookie = false
99
111
  @sign_in_guards = []
@@ -121,12 +133,20 @@ module Clearance
121
133
  end
122
134
  end
123
135
 
136
+ # The name of user parameter for the configured user model.
137
+ # This is derived from the `model_name` of the `user_model` setting.
138
+ # In the default configuration, this is `user`.
139
+ # @return [Symbol]
140
+ def user_parameter
141
+ user_model.model_name.singular.to_sym
142
+ end
143
+
124
144
  # The name of foreign key parameter for the configured user model.
125
145
  # This is derived from the `model_name` of the `user_model` setting.
126
146
  # In the default configuration, this is `user_id`.
127
147
  # @return [Symbol]
128
148
  def user_id_parameter
129
- "#{user_model.model_name.singular}_id".to_sym
149
+ "#{user_parameter}_id".to_sym
130
150
  end
131
151
 
132
152
  # @return [Boolean] are Clearance's built-in routes enabled?
@@ -138,12 +158,32 @@ module Clearance
138
158
  # This is called from the Clearance engine to reload the configured
139
159
  # user class during each request while in development mode, but only once
140
160
  # in production.
141
- # @private
161
+ #
162
+ # @api private
142
163
  def reload_user_model
143
164
  if @user_model.present?
144
165
  @user_model = @user_model.to_s.constantize
145
166
  end
146
167
  end
168
+
169
+ def rotate_csrf_on_sign_in?
170
+ if rotate_csrf_on_sign_in.nil?
171
+ warn <<-EOM.squish
172
+ Clearance's `rotate_csrf_on_sign_in` configuration setting is unset and
173
+ will be treated as `false`. Setting this value to `true` is
174
+ recommended to avoid session fixation attacks and will be the default
175
+ in Clearance 2.0. It is recommended that you opt-in to this setting
176
+ now and test your application. To silence this warning, set
177
+ `rotate_csrf_on_sign_in` to `true` or `false` in Clearance's
178
+ initializer.
179
+
180
+ For more information on session fixation, see:
181
+ https://www.owasp.org/index.php/Session_fixation
182
+ EOM
183
+ end
184
+
185
+ rotate_csrf_on_sign_in
186
+ end
147
187
  end
148
188
 
149
189
  # @return [Clearance::Configuration] Clearance's current configuration
@@ -1,5 +1,22 @@
1
1
  module Clearance
2
2
  module Constraints
3
+ # Can be applied to make a set of routes visible only to users that are
4
+ # signed in.
5
+ #
6
+ # # config/routes.rb
7
+ # constraints Clearance::Constraints::SignedIn.new do
8
+ # resources :posts
9
+ # end
10
+ #
11
+ # In the example above, requests to `/posts` from users that are not signed
12
+ # in will result in a 404. You can make additional assertions about the user
13
+ # by passing a block. For instance, if you want to require that the
14
+ # signed-in user be an admin:
15
+ #
16
+ # # config/routes.rb
17
+ # constraints Clearance::Constraints::SignedIn.new { |user| user.admin? } do
18
+ # resources :posts
19
+ # end
3
20
  class SignedIn
4
21
  def initialize(&block)
5
22
  @block = block || lambda { |user| true }
@@ -12,18 +29,22 @@ module Clearance
12
29
 
13
30
  private
14
31
 
32
+ # @api private
15
33
  def clearance_session
16
34
  @request.env[:clearance]
17
35
  end
18
36
 
37
+ # @api private
19
38
  def current_user
20
39
  clearance_session.current_user
21
40
  end
22
41
 
42
+ # @api private
23
43
  def current_user_fulfills_additional_requirements?
24
44
  @block.call current_user
25
45
  end
26
46
 
47
+ # @api private
27
48
  def signed_in?
28
49
  clearance_session.present? && clearance_session.signed_in?
29
50
  end
@@ -1,5 +1,15 @@
1
1
  module Clearance
2
2
  module Constraints
3
+ # Can be applied to make a set of routes visible only to users that are
4
+ # signed out.
5
+ #
6
+ # # config/routes.rb
7
+ # constraints Clearance::Constraints::SignedOut.new do
8
+ # resources :registrations, only: [:new, :create]
9
+ # end
10
+ #
11
+ # In the example above, requests to `/registrations/new` from users that are
12
+ # signed in will result in a 404.
3
13
  class SignedOut
4
14
  def matches?(request)
5
15
  @request = request
@@ -8,10 +18,12 @@ module Clearance
8
18
 
9
19
  private
10
20
 
21
+ # @api private
11
22
  def clearance_session
12
23
  @request.env[:clearance]
13
24
  end
14
25
 
26
+ # @api private
15
27
  def missing_session?
16
28
  clearance_session.nil?
17
29
  end
@@ -1,2 +1,14 @@
1
1
  require 'clearance/constraints/signed_in'
2
2
  require 'clearance/constraints/signed_out'
3
+
4
+ module Clearance
5
+ # Clearance provides Rails routing constraints that can control access and the
6
+ # visibility of routes at the routing layer. The {Constraints::SignedIn}
7
+ # constraint can be used to make routes visible only to signed in users. The
8
+ # {Constraints::SignedOut} constraint can be used to make routes visible only
9
+ # to signed out users.
10
+ #
11
+ # @see http://guides.rubyonrails.org/routing.html#advanced-constraints
12
+ module Constraints
13
+ end
14
+ end
@@ -2,6 +2,19 @@ require 'clearance/authentication'
2
2
  require 'clearance/authorization'
3
3
 
4
4
  module Clearance
5
+ # Adds clearance controller helpers to the controller it is mixed into.
6
+ #
7
+ # This exposes clearance controller and helper methods such as `current_user`.
8
+ # See {Authentication} and {Authorization} documentation for complete
9
+ # documentation on the methods.
10
+ #
11
+ # The `clearance:install` generator automatically adds this mixin to
12
+ # `ApplicationController`, which is the recommended configuration.
13
+ #
14
+ # class ApplicationController < ActionController::Base
15
+ # include Clearance::Controller
16
+ # end
17
+ #
5
18
  module Controller
6
19
  extend ActiveSupport::Concern
7
20
 
@@ -1,5 +1,14 @@
1
1
  module Clearance
2
+ # Runs as the base {SignInGuard} for all requests, regardless of configured
3
+ # {Configuration#sign_in_guards}.
2
4
  class DefaultSignInGuard < SignInGuard
5
+ # Runs the default sign in guard.
6
+ #
7
+ # If there is a value set in the clearance session object, then the guard
8
+ # returns {SuccessStatus}. Otherwise, it returns {FailureStatus} with the
9
+ # message returned by {#default_failure_message}.
10
+ #
11
+ # @return [SuccessStatus, FailureStatus]
3
12
  def call
4
13
  if session.signed_in?
5
14
  success
@@ -8,6 +17,14 @@ module Clearance
8
17
  end
9
18
  end
10
19
 
20
+ # The default failure message pulled from the i18n framework.
21
+ #
22
+ # Will use the value returned from the following i18n keys, in this order:
23
+ #
24
+ # * `clearance.controllers.sessions.bad_email_or_password`
25
+ # * `flashes.failure_after_create`
26
+ #
27
+ # @return [String]
11
28
  def default_failure_message
12
29
  I18n.t(
13
30
  :bad_email_or_password,
@@ -1,16 +1,29 @@
1
1
  require "clearance"
2
- require "rails"
2
+ require "rails/engine"
3
3
 
4
4
  module Clearance
5
+ # Makes Clearance behavior available to Rails apps on initialization. By using
6
+ # a Rails Engine rather than a Railtie, Clearance can automatically expose its
7
+ # own routes and views to the hosting application.
8
+ #
9
+ # Requiring `clearance` (likely by having it in your `Gemfile`) will
10
+ # automatically require the engine. You can opt-out of Clearance's internal
11
+ # routes by using {Configuration#routes=}. You can override the Clearance
12
+ # views by running `rails generate clearance:views`.
13
+ #
14
+ # In addition to providing routes and views, the Clearance engine:
15
+ #
16
+ # * Ensures `password` and `token` parameters are filtered out of Rails logs.
17
+ # * Mounts the {RackSession} middleware in the appropriate location
18
+ # * Reloads classes referenced in your {Configuration} on every request in
19
+ # development mode.
20
+ #
5
21
  class Engine < Rails::Engine
6
22
  initializer "clearance.filter" do |app|
7
23
  app.config.filter_parameters += [:password, :token]
8
24
  end
9
25
 
10
- config.app_middleware.insert_after(
11
- ActionDispatch::ParamsParser,
12
- Clearance::RackSession
13
- )
26
+ config.app_middleware.use(Clearance::RackSession)
14
27
 
15
28
  config.to_prepare do
16
29
  Clearance.configuration.reload_user_model
@@ -1,10 +1,14 @@
1
1
  module Clearance
2
2
  module PasswordStrategies
3
+ # Uses BCrypt to authenticate users and store encrypted passwords.
4
+ #
5
+ # The BCrypt cost (the measure of how many key expansion iterations BCrypt
6
+ # will perform) is automatically set to the minimum allowed value when
7
+ # Rails is operating in the test environment and the default cost in all
8
+ # other envionments. This provides a speed boost in tests.
3
9
  module BCrypt
4
10
  require 'bcrypt'
5
11
 
6
- extend ActiveSupport::Concern
7
-
8
12
  def authenticated?(password)
9
13
  if encrypted_password.present?
10
14
  ::BCrypt::Password.new(encrypted_password) == password
@@ -15,27 +19,18 @@ module Clearance
15
19
  @password = new_password
16
20
 
17
21
  if new_password.present?
18
- self.encrypted_password = encrypt(new_password)
22
+ cost = if defined?(::Rails) && ::Rails.env.test?
23
+ ::BCrypt::Engine::MIN_COST
24
+ else
25
+ ::BCrypt::Engine::DEFAULT_COST
26
+ end
27
+
28
+ self.encrypted_password = ::BCrypt::Password.create(
29
+ new_password,
30
+ cost: cost,
31
+ )
19
32
  end
20
33
  end
21
-
22
- private
23
-
24
- def encrypt(password)
25
- ::BCrypt::Password.create(password, cost: cost)
26
- end
27
-
28
- def cost
29
- if test_environment?
30
- ::BCrypt::Engine::MIN_COST
31
- else
32
- ::BCrypt::Engine::DEFAULT_COST
33
- end
34
- end
35
-
36
- def test_environment?
37
- defined?(::Rails) && ::Rails.env.test?
38
- end
39
34
  end
40
35
  end
41
36
  end