Skip to content

Commit a0d7c46

Browse files
committed
Add Lockable option to Devise
Locking Admin users after consecutive failed attempts is a good practice to prevent Brute Force password detection. This adds the necessary backbone (controller, routes and email template) so that using the lockable strategy with the extension requires minimal work over it.
1 parent 8d21a46 commit a0d7c46

File tree

6 files changed

+46
-4
lines changed

6 files changed

+46
-4
lines changed

app/mailers/spree/user_mailer.rb

+8
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,13 @@ def confirmation_instructions(user, token, _opts = {})
1313
@confirmation_url = spree.spree_user_confirmation_url(confirmation_token: token, host: @store.url)
1414
mail to: user.email, from: from_address(@store), subject: "#{@store.name} #{I18n.t(:subject, scope: [:devise, :mailer, :confirmation_instructions])}"
1515
end
16+
17+
def unlock_instructions(user, token, _opts = {})
18+
@store = Spree::Store.default
19+
@user = user
20+
21+
@unlock_url = spree.admin_unlock_url(unlock_token: token, host: @store.url)
22+
mail to: user.email, from: from_address(@store), subject: "#{@store.name} #{I18n.t(:subject, scope: [:devise, :mailer, :unlock_instructions])}"
23+
end
1624
end
1725
end

app/models/spree/user.rb

+2-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@ class User < Spree::Base
55
include UserMethods
66

77
devise :database_authenticatable, :registerable, :recoverable,
8-
:rememberable, :trackable, :validatable, :encryptable
8+
:rememberable, :trackable, :validatable, :encryptable,
9+
:lockable
910
devise :confirmable if Spree::Auth::Config[:confirmable]
1011

1112
if defined?(Spree::SoftDeletable)

config/initializers/devise.rb

+2-2
Original file line numberDiff line numberDiff line change
@@ -81,14 +81,14 @@
8181
# Defines which strategy will be used to lock an account.
8282
# :failed_attempts = Locks an account after a number of failed attempts to sign in.
8383
# :none = No lock strategy. You should handle locking by yourself.
84-
# config.lock_strategy = :failed_attempts
84+
config.lock_strategy = :none
8585

8686
# Defines which strategy will be used to unlock an account.
8787
# :email = Sends an unlock link to the user email
8888
# :time = Re-enables login after a certain amount of time (see :unlock_in below)
8989
# :both = Enables both strategies
9090
# :none = No unlock strategy. You should handle unlocking by yourself.
91-
# config.unlock_strategy = :both
91+
config.unlock_strategy = :both
9292

9393
# Number of authentication tries before locking an account if lock_strategy
9494
# is failed attempts.

config/routes.rb

+5-1
Original file line numberDiff line numberDiff line change
@@ -46,7 +46,8 @@
4646
path_names: { sign_out: 'logout' },
4747
controllers: {
4848
sessions: 'spree/admin/user_sessions',
49-
passwords: 'spree/admin/user_passwords'
49+
passwords: 'spree/admin/user_passwords',
50+
unlocks: 'spree/admin/user_unlocks'
5051
},
5152
router_name: :spree
5253
})
@@ -61,6 +62,9 @@
6162
post '/password/recover', to: 'user_passwords#create', as: :reset_password
6263
get '/password/change', to: 'user_passwords#edit', as: :edit_password
6364
put '/password/change', to: 'user_passwords#update', as: :update_password
65+
66+
get '/unlock', to: 'user_unlocks#show', as: :unlock
67+
post '/unlock', to: 'user_unlocks#create'
6468
end
6569
end
6670
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# frozen_string_literal: true
2+
3+
module Spree
4+
module Admin
5+
class UserUnlocksController < Devise::UnlocksController
6+
helper 'spree/base'
7+
8+
include Spree::Core::ControllerHelpers::Auth
9+
include Spree::Core::ControllerHelpers::Common
10+
include Spree::Core::ControllerHelpers::Store
11+
12+
helper 'spree/admin/navigation'
13+
layout 'spree/layouts/admin'
14+
15+
private
16+
17+
def after_unlock_path_for(_resource)
18+
admin_login_path if is_navigational_format?
19+
end
20+
end
21+
end
22+
end
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
<p>Hello <%= @user.email %>!</p>
2+
3+
<p>Your account has been locked due to an excessive number of unsuccessful sign in attempts.</p>
4+
5+
<p>Click the link below to unlock your account:</p>
6+
7+
<p><%= link_to 'Unlock my account', @unlock_url %></p>

0 commit comments

Comments
 (0)