clearance 2.1.0 → 2.4.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 (41) hide show
  1. checksums.yaml +4 -4
  2. data/.erb-lint.yml +5 -0
  3. data/.github/workflows/tests.yml +52 -0
  4. data/Appraisals +14 -19
  5. data/Gemfile +11 -7
  6. data/Gemfile.lock +140 -85
  7. data/NEWS.md +62 -0
  8. data/README.md +23 -12
  9. data/RELEASING.md +25 -0
  10. data/Rakefile +6 -1
  11. data/app/controllers/clearance/passwords_controller.rb +2 -3
  12. data/app/views/clearance_mailer/change_password.html.erb +2 -2
  13. data/app/views/clearance_mailer/change_password.text.erb +2 -2
  14. data/app/views/passwords/edit.html.erb +1 -1
  15. data/clearance.gemspec +1 -0
  16. data/gemfiles/rails_5.0.gemfile +10 -9
  17. data/gemfiles/rails_5.1.gemfile +11 -10
  18. data/gemfiles/rails_5.2.gemfile +11 -10
  19. data/gemfiles/rails_6.0.gemfile +11 -10
  20. data/gemfiles/rails_6.1.gemfile +21 -0
  21. data/lib/clearance/back_door.rb +2 -1
  22. data/lib/clearance/configuration.rb +19 -0
  23. data/lib/clearance/password_strategies.rb +2 -5
  24. data/lib/clearance/password_strategies/argon2.rb +23 -0
  25. data/lib/clearance/rack_session.rb +1 -1
  26. data/lib/clearance/session.rb +24 -12
  27. data/lib/clearance/user.rb +11 -2
  28. data/lib/clearance/version.rb +1 -1
  29. data/lib/generators/clearance/install/install_generator.rb +4 -1
  30. data/spec/clearance/back_door_spec.rb +20 -4
  31. data/spec/clearance/rack_session_spec.rb +1 -2
  32. data/spec/clearance/session_spec.rb +116 -43
  33. data/spec/configuration_spec.rb +28 -0
  34. data/spec/generators/clearance/install/install_generator_spec.rb +8 -2
  35. data/spec/mailers/clearance_mailer_spec.rb +33 -0
  36. data/spec/models/user_spec.rb +29 -0
  37. data/spec/password_strategies/argon2_spec.rb +79 -0
  38. data/spec/support/clearance.rb +11 -0
  39. data/spec/support/request_with_remember_token.rb +8 -6
  40. metadata +29 -4
  41. data/.travis.yml +0 -27
@@ -55,4 +55,37 @@ describe ClearanceMailer do
55
55
  text: I18n.t("clearance_mailer.change_password.link_text")
56
56
  )
57
57
  end
58
+
59
+ context "when using a custom model" do
60
+ it "contains a link for a custom model" do
61
+ define_people_routes
62
+ Person = Class.new(User)
63
+ person = Person.new(email: "person@example.com", password: "password")
64
+
65
+ person.forgot_password!
66
+ host = ActionMailer::Base.default_url_options[:host]
67
+ link = "http://#{host}/people/#{person.id}/password/edit" \
68
+ "?token=#{person.confirmation_token}"
69
+
70
+ email = ClearanceMailer.change_password(person)
71
+
72
+ expect(email.text_part.body).to include(link)
73
+ expect(email.html_part.body).to include(link)
74
+
75
+ Object.send(:remove_const, :Person)
76
+ Rails.application.reload_routes!
77
+ end
78
+
79
+ def define_people_routes
80
+ Rails.application.routes.draw do
81
+ resources :people, controller: "clearance/users", only: :create do
82
+ resource(
83
+ :password,
84
+ controller: "clearance/passwords",
85
+ only: %i[edit update],
86
+ )
87
+ end
88
+ end
89
+ end
90
+ end
58
91
  end
@@ -47,6 +47,35 @@ describe User do
47
47
  expect(User.authenticate(user.email, "bad_password")).to be_nil
48
48
  end
49
49
 
50
+ it "takes the same amount of time to authenticate regardless of whether user exists" do
51
+ user = create(:user)
52
+ password = user.password
53
+
54
+ user_exists_time = Benchmark.realtime do
55
+ User.authenticate(user.email, password)
56
+ end
57
+
58
+ user_does_not_exist_time = Benchmark.realtime do
59
+ User.authenticate("bad_email@example.com", password)
60
+ end
61
+
62
+ expect(user_does_not_exist_time). to be_within(0.01).of(user_exists_time)
63
+ end
64
+
65
+ it "takes the same amount of time to fail authentication regardless of whether user exists" do
66
+ user = create(:user)
67
+
68
+ user_exists_time = Benchmark.realtime do
69
+ User.authenticate(user.email, "bad_password")
70
+ end
71
+
72
+ user_does_not_exist_time = Benchmark.realtime do
73
+ User.authenticate("bad_email@example.com", "bad_password")
74
+ end
75
+
76
+ expect(user_does_not_exist_time). to be_within(0.01).of(user_exists_time)
77
+ end
78
+
50
79
  it "is retrieved via a case-insensitive search" do
51
80
  user = create(:user)
52
81
 
@@ -0,0 +1,79 @@
1
+ require "spec_helper"
2
+
3
+ describe Clearance::PasswordStrategies::Argon2 do
4
+ include FakeModelWithPasswordStrategy
5
+
6
+ describe "#password=" do
7
+ it "encrypts the password into encrypted_password" do
8
+ stub_argon2_password
9
+ model_instance = fake_model_with_argon2_strategy
10
+
11
+ model_instance.password = password
12
+
13
+ expect(model_instance.encrypted_password).to eq encrypted_password
14
+ end
15
+
16
+ it "encrypts with Argon2 using default cost in non test environments" do
17
+ hasher = stub_argon2_password
18
+ model_instance = fake_model_with_argon2_strategy
19
+ allow(Rails).to receive(:env).
20
+ and_return(ActiveSupport::StringInquirer.new("production"))
21
+
22
+ model_instance.password = password
23
+
24
+ expect(hasher).to have_received(:create).with(password)
25
+ end
26
+
27
+ it "encrypts with Argon2 using minimum cost in test environment" do
28
+ hasher = stub_argon2_password
29
+ model_instance = fake_model_with_argon2_strategy
30
+
31
+ model_instance.password = password
32
+
33
+ expect(hasher).to have_received(:create).with(password)
34
+ end
35
+
36
+ def stub_argon2_password
37
+ hasher = double(Argon2::Password)
38
+ allow(hasher).to receive(:create).and_return(encrypted_password)
39
+ allow(Argon2::Password).to receive(:new).and_return(hasher)
40
+ hasher
41
+ end
42
+
43
+ def encrypted_password
44
+ @encrypted_password ||= double("encrypted password")
45
+ end
46
+ end
47
+
48
+ describe "#authenticated?" do
49
+ context "given a password" do
50
+ it "is authenticated with Argon2" do
51
+ model_instance = fake_model_with_argon2_strategy
52
+
53
+ model_instance.password = password
54
+
55
+ expect(model_instance).to be_authenticated(password)
56
+ end
57
+ end
58
+
59
+ context "given no password" do
60
+ it "is not authenticated" do
61
+ model_instance = fake_model_with_argon2_strategy
62
+
63
+ password = nil
64
+
65
+ expect(model_instance).not_to be_authenticated(password)
66
+ end
67
+ end
68
+ end
69
+
70
+ def fake_model_with_argon2_strategy
71
+ @fake_model_with_argon2_strategy ||= fake_model_with_password_strategy(
72
+ Clearance::PasswordStrategies::Argon2,
73
+ )
74
+ end
75
+
76
+ def password
77
+ "password"
78
+ end
79
+ end
@@ -4,6 +4,17 @@ Clearance.configure do |config|
4
4
  # need an empty block to initialize the configuration object
5
5
  end
6
6
 
7
+ # NOTE: to run the entire suite with signed cookies
8
+ # you can set the signed_cookie default to true
9
+ # and run all specs.
10
+ # However, to fake the actual signing process you
11
+ # can monkey-patch ActionDispatch so signed cookies
12
+ # behave like normal ones
13
+ #
14
+ # class ActionDispatch::Cookies::CookieJar
15
+ # def signed; self; end
16
+ # end
17
+
7
18
  module Clearance
8
19
  module Test
9
20
  module Redirects
@@ -1,11 +1,13 @@
1
1
  module RememberTokenHelpers
2
2
  def request_with_remember_token(remember_token)
3
- cookies = {
4
- 'action_dispatch.cookies' => {
5
- Clearance.configuration.cookie_name => remember_token
6
- }
7
- }
8
- env = { clearance: Clearance::Session.new(cookies) }
3
+ cookies = ActionDispatch::Request.new({}).cookie_jar
4
+ if Clearance.configuration.signed_cookie
5
+ cookies.signed[Clearance.configuration.cookie_name] = remember_token
6
+ else
7
+ cookies[Clearance.configuration.cookie_name] = remember_token
8
+ end
9
+
10
+ env = { clearance: Clearance::Session.new(cookies.request.env) }
9
11
  Rack::Request.new env
10
12
  end
11
13
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: clearance
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.0
4
+ version: 2.4.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Dan Croak
@@ -25,7 +25,7 @@ authors:
25
25
  autorequire:
26
26
  bindir: bin
27
27
  cert_chain: []
28
- date: 2019-12-19 00:00:00.000000000 Z
28
+ date: 2021-04-09 00:00:00.000000000 Z
29
29
  dependencies:
30
30
  - !ruby/object:Gem::Dependency
31
31
  name: bcrypt
@@ -41,6 +41,26 @@ dependencies:
41
41
  - - ">="
42
42
  - !ruby/object:Gem::Version
43
43
  version: 3.1.1
44
+ - !ruby/object:Gem::Dependency
45
+ name: argon2
46
+ requirement: !ruby/object:Gem::Requirement
47
+ requirements:
48
+ - - "~>"
49
+ - !ruby/object:Gem::Version
50
+ version: '2.0'
51
+ - - ">="
52
+ - !ruby/object:Gem::Version
53
+ version: 2.0.2
54
+ type: :runtime
55
+ prerelease: false
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ requirements:
58
+ - - "~>"
59
+ - !ruby/object:Gem::Version
60
+ version: '2.0'
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ version: 2.0.2
44
64
  - !ruby/object:Gem::Dependency
45
65
  name: email_validator
46
66
  requirement: !ruby/object:Gem::Requirement
@@ -124,8 +144,9 @@ extra_rdoc_files:
124
144
  - LICENSE
125
145
  - README.md
126
146
  files:
147
+ - ".erb-lint.yml"
148
+ - ".github/workflows/tests.yml"
127
149
  - ".gitignore"
128
- - ".travis.yml"
129
150
  - ".yardopts"
130
151
  - Appraisals
131
152
  - CONTRIBUTING.md
@@ -134,6 +155,7 @@ files:
134
155
  - LICENSE
135
156
  - NEWS.md
136
157
  - README.md
158
+ - RELEASING.md
137
159
  - Rakefile
138
160
  - app/controllers/clearance/base_controller.rb
139
161
  - app/controllers/clearance/passwords_controller.rb
@@ -162,6 +184,7 @@ files:
162
184
  - gemfiles/rails_5.1.gemfile
163
185
  - gemfiles/rails_5.2.gemfile
164
186
  - gemfiles/rails_6.0.gemfile
187
+ - gemfiles/rails_6.1.gemfile
165
188
  - lib/clearance.rb
166
189
  - lib/clearance/authentication.rb
167
190
  - lib/clearance/authorization.rb
@@ -174,6 +197,7 @@ files:
174
197
  - lib/clearance/default_sign_in_guard.rb
175
198
  - lib/clearance/engine.rb
176
199
  - lib/clearance/password_strategies.rb
200
+ - lib/clearance/password_strategies/argon2.rb
177
201
  - lib/clearance/password_strategies/bcrypt.rb
178
202
  - lib/clearance/rack_session.rb
179
203
  - lib/clearance/rspec.rb
@@ -250,6 +274,7 @@ files:
250
274
  - spec/helpers/helper_helpers_spec.rb
251
275
  - spec/mailers/clearance_mailer_spec.rb
252
276
  - spec/models/user_spec.rb
277
+ - spec/password_strategies/argon2_spec.rb
253
278
  - spec/password_strategies/bcrypt_spec.rb
254
279
  - spec/password_strategies/password_strategies_spec.rb
255
280
  - spec/requests/authentication_cookie_spec.rb
@@ -286,7 +311,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
286
311
  - !ruby/object:Gem::Version
287
312
  version: '0'
288
313
  requirements: []
289
- rubygems_version: 3.0.3
314
+ rubygems_version: 3.1.2
290
315
  signing_key:
291
316
  specification_version: 4
292
317
  summary: Rails authentication & authorization with email & password.
data/.travis.yml DELETED
@@ -1,27 +0,0 @@
1
- cache: bundler
2
-
3
- language:
4
- - ruby
5
-
6
- rvm:
7
- - 2.4.9
8
- - 2.5.7
9
- - 2.6.5
10
-
11
- gemfile:
12
- - gemfiles/rails_5.0.gemfile
13
- - gemfiles/rails_5.1.gemfile
14
- - gemfiles/rails_5.2.gemfile
15
- - gemfiles/rails_6.0.gemfile
16
-
17
- install:
18
- - "bin/setup"
19
-
20
- branches:
21
- only:
22
- - master
23
-
24
- matrix:
25
- exclude:
26
- - rvm: 2.4.9
27
- gemfile: gemfiles/rails_6.0.gemfile