minimalist_authentication 2.6.2 → 3.0.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 05b2b926522ced063d72007717f98e12af465740245ba02a61bdcc75e53a5cab
4
- data.tar.gz: c42e2529f6211ea1c2d81958d96a4b3711173e7b7da4ac32482cb0f2b8ca3fcb
3
+ metadata.gz: a82f3a3833f400b37555173885d052000dfbd5e4a67da90068384558f8d97705
4
+ data.tar.gz: 48b819ddbb26a5cb5deaa03c5cd3ef943394e93d6390286d3f30cbae7e5e8477
5
5
  SHA512:
6
- metadata.gz: 53254b7754bcbe07608c3b779c42737eaa6243e25a86aa7df21a7cd576e9cfbb1d20c3b63470ed59e69f0a7ee659e4c0075f60b493dfd1e3c28d6e0ede1fa167
7
- data.tar.gz: bfcd187bc8c0f4602e0040c45bdead5bd3138dc1134a173bf449bd84d37b05c7c954595831d39835c7694b35c04d87d86a746701332d52a27c8d6e6754529e4b
6
+ metadata.gz: c867bd7daebdce0f0998e78db4d05ed89bd8d3767d6bb0dc79e362f74ca8e2ac43e930dffb0f396d3d1f4f6b517d26fee00e03e06c32a8afd4b52fb0d03984b7
7
+ data.tar.gz: de8329fcb5b6bd2d01e9a421818952e6f362d4ff16a3e060d30e5b3afbd4751d56e4c0d37b1a3d80d917baf48dea36b407a2fbfc8f647019fa896529d82bf3a2
data/README.md CHANGED
@@ -16,12 +16,12 @@ $ bundle
16
16
 
17
17
  Create a user model with **email** for an identifier:
18
18
  ```bash
19
- bin/rails generate model user active:boolean email:string password_hash:string last_logged_in_at:datetime
19
+ bin/rails generate model user active:boolean email:string password_digest:string last_logged_in_at:datetime
20
20
  ```
21
21
 
22
22
  OR create a user model with **username** for an identifier:
23
23
  ```bash
24
- bin/rails generate model user active:boolean username:string password_hash:string last_logged_in_at:datetime
24
+ bin/rails generate model user active:boolean username:string password_digest:string last_logged_in_at:datetime
25
25
  ```
26
26
 
27
27
 
@@ -79,12 +79,11 @@ end
79
79
 
80
80
 
81
81
  ## Fixtures
82
- Use **MinimalistAuthentication::Password.create** to create a password for
83
- fixture users.
82
+ Use **MinimalistAuthentication::TestHelper::PASSWORD_DIGEST** to create a password_digest for fixture users.
84
83
  ```yaml
85
84
  example_user:
86
- email: user@example.com
87
- password_hash: <%= MinimalistAuthentication::Password.create("test-password") %>
85
+ email: user@example.com
86
+ password_digest: <%= MinimalistAuthentication::TestHelper::PASSWORD_DIGEST %>
88
87
  ```
89
88
 
90
89
 
@@ -124,6 +123,8 @@ bin/rails generate migration AddEmailVerifiedAtToUsers email_verified_at:datetim
124
123
 
125
124
 
126
125
  ## Conversions
126
+
127
+ ### Upgrading to Version 2.0
127
128
  Pre 2.0 versions of MinimalistAuthentication supported multiple hash algorithms
128
129
  and stored the hashed password and salt as separate fields in the database
129
130
  (crypted_password and salt). The current version of MinimalistAuthentication
@@ -141,10 +142,26 @@ MinimalistAuthentication::Conversions::MergePasswordHash.run!
141
142
  When the conversion is complete the **crypted_password**, **salt**, and
142
143
  **using_digest_version** fields can safely be removed.
143
144
 
145
+ ### Upgrading to Version 3.0
146
+ Version 3.0 of MinimalistAuthentication uses the Rails has_secure_password for authentication. This change requires either renaming the **password_hash** column to **password_digest** or adding an alias_attribute to map **password_digest** to **password_hash**.
144
147
 
145
- ## Build
146
- [![Build Status](https://travis-ci.org/wwidea/minimalist_authentication.svg?branch=master)](https://travis-ci.org/wwidea/minimalist_authentication)
148
+ #### Rename the **password_hash** column to **password_digest**
149
+ Add a migration to rename the column in your users table:
150
+ ```bash
151
+ bin/rails generate migration rename_users_password_hash_to_password_digest
152
+ ```
147
153
 
154
+ Update the change method:
155
+ ```ruby
156
+ def change
157
+ rename_column :users, :password_hash, :password_digest
158
+ end
159
+ ```
160
+
161
+ #### Alternatively, add **alias_attribute** to your user model
162
+ ```ruby
163
+ alias_attribute :password_digest, :password_hash
164
+ ```
148
165
 
149
166
  ## License
150
167
  The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT)..
@@ -1,5 +1,7 @@
1
1
  <h1>Edit Password</h1>
2
2
 
3
+ <%= @user.errors.full_messages if @user.errors.any? %>
4
+
3
5
  <%= form_for @user, as: :user, url: user_password_path(@user, token: @token), html: { method: :put } do |form| %>
4
6
  <div>
5
7
  <%= form.label :password %>
@@ -39,7 +39,7 @@ module MinimalistAuthentication
39
39
  # Defaults to true
40
40
  attr_accessor :request_email
41
41
 
42
- # Vefify users email address at login.
42
+ # Verify users email address at login.
43
43
  # Defaults to true.
44
44
  attr_accessor :verify_email
45
45
 
@@ -48,9 +48,5 @@ module MinimalistAuthentication
48
48
  def store_location
49
49
  session["return_to"] = url_for(request.params.merge(format: :html, only_path: true))
50
50
  end
51
-
52
- def redirect_back_or_default(default)
53
- redirect_to(session.delete("return_to") || default)
54
- end
55
51
  end
56
52
  end
@@ -5,6 +5,9 @@ module MinimalistAuthentication
5
5
  extend ActiveSupport::Concern
6
6
 
7
7
  included do
8
+ # URL to redirect to after successful login
9
+ attr_accessor :return_to
10
+
8
11
  skip_before_action :authorization_required, only: %i[new create]
9
12
  before_action :redirect_logged_in_users, only: :new
10
13
  end
@@ -23,7 +26,7 @@ module MinimalistAuthentication
23
26
  end
24
27
 
25
28
  def destroy
26
- scrub_session!
29
+ reset_session
27
30
  redirect_to logout_redirect_to, notice: t(".notice"), status: :see_other
28
31
  end
29
32
 
@@ -38,7 +41,8 @@ module MinimalistAuthentication
38
41
  end
39
42
 
40
43
  def log_in_user
41
- scrub_session!
44
+ self.return_to = session["return_to"]
45
+ reset_session
42
46
  authenticated_user.logged_in
43
47
  session[MinimalistAuthentication.configuration.session_key] = authenticated_user.id
44
48
  end
@@ -62,7 +66,7 @@ module MinimalistAuthentication
62
66
  end
63
67
 
64
68
  def after_authentication_success
65
- redirect_back_or_default(login_redirect_to)
69
+ redirect_to return_to || login_redirect_to
66
70
  end
67
71
 
68
72
  def attempting_to_verify?
@@ -80,12 +84,6 @@ module MinimalistAuthentication
80
84
  user_params.values_at(*MinimalistAuthentication::Authenticator::LOGIN_FIELDS).compact.first
81
85
  end
82
86
 
83
- def scrub_session!
84
- (session.keys - %w[session_id return_to]).each do |key|
85
- session.delete(key)
86
- end
87
- end
88
-
89
87
  def login_redirect_to
90
88
  send(MinimalistAuthentication.configuration.login_redirect_path)
91
89
  end
@@ -3,6 +3,7 @@
3
3
  module MinimalistAuthentication
4
4
  module TestHelper
5
5
  PASSWORD = "test-password"
6
+ PASSWORD_DIGEST = BCrypt::Password.create(PASSWORD, cost: BCrypt::Engine::MIN_COST)
6
7
 
7
8
  def login_as(user_fixture_name, password = PASSWORD)
8
9
  post session_path, params: { user: { email: users(user_fixture_name).email, password: } }
@@ -9,20 +9,16 @@ module MinimalistAuthentication
9
9
  GUEST_USER_EMAIL = "guest"
10
10
 
11
11
  included do
12
- # Stores the plain text password.
13
- attribute :password, :string
12
+ has_secure_password validations: false
14
13
 
15
14
  # Force validations for a blank password.
16
15
  attribute :password_required, :boolean, default: false
17
16
 
18
- # Hashes and stores the password on save.
19
- before_save :hash_password
20
-
21
17
  # Email validations
22
18
  validates(
23
19
  :email,
24
20
  format: { allow_blank: true, with: URI::MailTo::EMAIL_REGEXP },
25
- uniqueness: { allow_blank: true, case_sensitive: false, scope: :active },
21
+ uniqueness: { allow_blank: true, case_sensitive: false },
26
22
  if: :validate_email?
27
23
  )
28
24
  validates(:email, presence: true, if: :validate_email_presence?)
@@ -35,6 +31,7 @@ module MinimalistAuthentication
35
31
  presence: true,
36
32
  if: :validate_password?
37
33
  )
34
+ validate :password_exclusivity, if: :password?
38
35
 
39
36
  # Active scope
40
37
  scope :active, ->(state = true) { where(active: state) }
@@ -42,14 +39,6 @@ module MinimalistAuthentication
42
39
  end
43
40
 
44
41
  module ClassMethods
45
- def authenticate(params)
46
- ActiveSupport::Deprecation.warn(<<-MSG.squish)
47
- Calling #{MinimalistAuthentication.configuration.user_model_name}::authenticate is deprecated.
48
- Use MinimalistAuthentication::Authenticator.authenticated_user instead.
49
- MSG
50
- MinimalistAuthentication::Authenticator.authenticated_user(params)
51
- end
52
-
53
42
  # Returns a frozen user with the email set to GUEST_USER_EMAIL.
54
43
  def guest
55
44
  new(email: GUEST_USER_EMAIL).freeze
@@ -61,18 +50,11 @@ module MinimalistAuthentication
61
50
  !active?
62
51
  end
63
52
 
64
- # Returns true if password matches the hashed_password, otherwise returns false. Upon successful
65
- # authentication the user's password_hash is updated if required.
53
+ # Returns true if password matches the hashed_password, otherwise returns false.
66
54
  def authenticated?(password)
67
- return false unless password_object == password
68
-
69
- update_hash!(password) if password_object.stale?
70
- true
71
- end
72
-
73
- def logged_in
74
- # Use update_column to avoid updated_on trigger
75
- update_column(:last_logged_in_at, Time.current)
55
+ authenticate(password)
56
+ rescue ::BCrypt::Errors::InvalidHash
57
+ false
76
58
  end
77
59
 
78
60
  # Check if user is a guest based on their email attribute
@@ -80,9 +62,9 @@ module MinimalistAuthentication
80
62
  email == GUEST_USER_EMAIL
81
63
  end
82
64
 
83
- def is_guest? # rubocop:disable Naming/PredicateName
84
- ActiveSupport::Deprecation.warn("Calling #is_guest? is deprecated. Use #guest? instead")
85
- guest?
65
+ def logged_in
66
+ # Use update_column to avoid updated_on trigger
67
+ update_column(:last_logged_in_at, Time.current)
86
68
  end
87
69
 
88
70
  # Minimum password length
@@ -91,48 +73,39 @@ module MinimalistAuthentication
91
73
  # Maximum password length
92
74
  def password_maximum = 40
93
75
 
94
- private
95
-
96
- # Set self.password to password, hash, and save if user is valid.
97
- def update_hash!(password)
98
- self.password = password
99
- return unless valid?
100
-
101
- hash_password
102
- save
76
+ # Checks for password presence
77
+ def password?
78
+ password.present?
103
79
  end
104
80
 
105
- # Hash password and store in hash_password unless password is blank.
106
- def hash_password
107
- return if password.blank?
108
-
109
- self.password_hash = Password.create(password)
110
- end
81
+ private
111
82
 
112
- # Returns a MinimalistAuthentication::Password object.
113
- def password_object
114
- Password.new(password_hash)
83
+ # Ensure password does not match username or email.
84
+ def password_exclusivity
85
+ %w[username email].each do |field|
86
+ errors.add(:password, "can not match #{field}") if password.casecmp?(try(field))
87
+ end
115
88
  end
116
89
 
117
90
  # Require password for active users that either do no have a password hash
118
91
  # stored OR are attempting to set a new password. Set **password_required**
119
92
  # to true to force validations even when the password field is blank.
120
93
  def validate_password?
121
- active? && (password_hash.blank? || password? || password_required?)
94
+ active? && (password_digest.blank? || password? || password_required?)
122
95
  end
123
96
 
124
- # Validate email for active users.
97
+ # Validate email for all users.
125
98
  # Applications can turn off email validation by setting the validate_email
126
99
  # configuration attribute to false.
127
100
  def validate_email?
128
- MinimalistAuthentication.configuration.validate_email && active?
101
+ MinimalistAuthentication.configuration.validate_email
129
102
  end
130
103
 
131
104
  # Validate email presence for active users.
132
105
  # Applications can turn off email presence validation by setting
133
106
  # validate_email_presence configuration attribute to false.
134
107
  def validate_email_presence?
135
- MinimalistAuthentication.configuration.validate_email_presence && validate_email?
108
+ MinimalistAuthentication.configuration.validate_email_presence && validate_email? && active?
136
109
  end
137
110
  end
138
111
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module MinimalistAuthentication
4
- VERSION = "2.6.2"
4
+ VERSION = "3.0.0"
5
5
  end
@@ -6,9 +6,6 @@ require "minimalist_authentication/configuration"
6
6
  require "minimalist_authentication/user"
7
7
  require "minimalist_authentication/verifiable_token"
8
8
  require "minimalist_authentication/email_verification"
9
- require "minimalist_authentication/password"
10
- require "minimalist_authentication/null_password"
11
9
  require "minimalist_authentication/controller"
12
10
  require "minimalist_authentication/sessions"
13
11
  require "minimalist_authentication/test_helper"
14
- require "minimalist_authentication/conversions/merge_password_hash"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: minimalist_authentication
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.6.2
4
+ version: 3.0.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Aaron Baldwin
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2024-09-22 00:00:00.000000000 Z
12
+ date: 2024-11-03 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: bcrypt
@@ -84,8 +84,6 @@ files:
84
84
  - lib/minimalist_authentication/conversions/merge_password_hash.rb
85
85
  - lib/minimalist_authentication/email_verification.rb
86
86
  - lib/minimalist_authentication/engine.rb
87
- - lib/minimalist_authentication/null_password.rb
88
- - lib/minimalist_authentication/password.rb
89
87
  - lib/minimalist_authentication/sessions.rb
90
88
  - lib/minimalist_authentication/test_helper.rb
91
89
  - lib/minimalist_authentication/user.rb
@@ -1,10 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module MinimalistAuthentication
4
- class NullPassword
5
- # does not match any object
6
- def ==(_other)
7
- false
8
- end
9
- end
10
- end
@@ -1,46 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module MinimalistAuthentication
4
- class Password
5
- class << self
6
- # Create a bcrypt password hash with a calibrated cost factor.
7
- def create(secret)
8
- new ::BCrypt::Engine.hash_secret(secret, BCrypt::Engine.generate_salt(cost))
9
- end
10
-
11
- # Cache the calibrated bcrypt cost factor.
12
- def cost
13
- @cost ||= calibrate_cost
14
- end
15
-
16
- private
17
-
18
- # Calibrates cost so that new user passwords can automatically take
19
- # advantage of faster server hardware in the future.
20
- # Sets cost to BCrypt::Engine::MIN_COST in the test environment
21
- def calibrate_cost
22
- ::Rails.env.test? ? ::BCrypt::Engine::MIN_COST : ::BCrypt::Engine.calibrate(750)
23
- end
24
- end
25
-
26
- attr_accessor :bcrypt_password
27
-
28
- # Returns a password object wrapping a valid BCrypt password or a NullPassword
29
- def initialize(password_hash)
30
- self.bcrypt_password = ::BCrypt::Password.new(password_hash)
31
- rescue ::BCrypt::Errors::InvalidHash
32
- self.bcrypt_password = NullPassword.new
33
- end
34
-
35
- # Delegate methods to bcrypt_password
36
- delegate :==, :to_s, :cost, to: :bcrypt_password
37
-
38
- # Temporary access to checksum and salt for backwards compatibility
39
- delegate :checksum, :salt, to: :bcrypt_password
40
-
41
- # Checks if the password_hash cost factor is less than the current cost.
42
- def stale?
43
- cost < self.class.cost
44
- end
45
- end
46
- end