In this chapter, you will configure the app to lock admins after an excessive number of unsuccessful logins, just as you already did for users in the previous chapter.
Enter the command "git checkout -b 09-13-admins_lock".
- Enter the command "rails generate integration_test admins_lock".
- Replace the contents of test/integration/admins_lock_test.rb with the following code:
# rubocop:disable Metrics/ClassLength
require 'test_helper'
require 'timecop'
class AdminsLockTest < ActionDispatch::IntegrationTest
N_WARNING = 5 # Number of incorrect logins for triggering warning
def login_incorrect_super
login_admin('ewoods', 'Yale Law School', false)
end
def login_incorrect_regular
login_admin('pbonafonte', 'evil stepmother', false)
end
def login_correct_super
login_admin('ewoods', 'endorphins', false)
end
def login_correct_regular
login_admin('pbonafonte', "Neptune's Beauty Nook", false)
end
def lock_super
N_WARNING.times do
login_incorrect_super
end
assert page.has_text?('You have one more attempt before your account is locked.')
login_incorrect_super
assert page.has_text?('Your account is locked.')
login_correct_super
assert page.has_text?('Your account is locked.')
end
def lock_regular
N_WARNING.times do
login_incorrect_regular
end
assert page.has_text?('You have one more attempt before your account is locked.')
login_incorrect_regular
assert page.has_text?('Your account is locked.')
login_correct_regular
assert page.has_text?('Your account is locked.')
end
test 'unlock request page has expected content' do
visit root_path
click_on 'Login'
click_on 'Admin Login'
click_on "Didn't receive unlock instructions?"
assert page.has_css?('title', text: full_title('Admin Unlock'), visible: false)
assert page.has_css?('h1', text: 'Admin Unlock')
end
test 'super admin can be unlocked by time' do
lock_super
t_lock = Time.now
t29 = t_lock + 29.minutes
t31 = t_lock + 31.minutes
# 29 minutes after the lock begins
Timecop.travel(t29)
login_correct_super
assert page.has_text?('Your account is locked.')
# 31 minutes after the lock begins
Timecop.travel(t31)
login_correct_super
assert page.has_text?('Signed in successfully.')
assert page.has_text?('You are logged in as an admin (ewoods).')
Timecop.return
end
test 'regular admin can be unlocked by time' do
lock_regular
t_lock = Time.now
t29 = t_lock + 29.minutes
t31 = t_lock + 31.minutes
# 29 minutes after the lock begins
Timecop.travel(t29)
login_correct_regular
assert page.has_text?('Your account is locked.')
# 31 minutes after the lock begins
Timecop.travel(t31)
login_correct_regular
assert page.has_text?('Signed in successfully.')
assert page.has_text?('You are logged in as an admin (pbonafonte).')
Timecop.return
end
test 'super admin can request another unlock link' do
lock_super
# Lose email
clear_emails # Clear the message queue
# Request unlock instructions
visit root_path
click_on 'Login'
click_on 'Admin Login'
click_on "Didn't receive unlock instructions?"
fill_in('Email', with: '[email protected]')
click_on 'Resend unlock instructions'
# Follow unlock instructions
open_email('[email protected]')
current_email.click_link 'Unlock my account'
assert page.has_text?('Your account has been unlocked successfully.')
assert page.has_text?('Please sign in to continue.')
clear_emails # Clear the message queue
# Login
login_correct_super
assert page.has_text?('Signed in successfully.')
assert page.has_text?('You are logged in as an admin (ewoods).')
clear_emails # Clear the message queue
end
test 'regular admin can request another unlock link' do
lock_regular
# Lose email
clear_emails # Clear the message queue
# Request unlock instructions
visit root_path
click_on 'Login'
click_on 'Admin Login'
click_on "Didn't receive unlock instructions?"
fill_in('Email', with: '[email protected]')
click_on 'Resend unlock instructions'
# Follow unlock instructions
open_email('[email protected]')
current_email.click_link 'Unlock my account'
assert page.has_text?('Your account has been unlocked successfully.')
assert page.has_text?('Please sign in to continue.')
clear_emails # Clear the message queue
# Login
login_correct_regular
assert page.has_text?('Signed in successfully.')
assert page.has_text?('You are logged in as an admin (pbonafonte).')
clear_emails # Clear the message queue
end
end
# rubocop:enable Metrics/ClassLength
- Enter the command "sh build_fast.sh".
- Enter the command "alias test1='(command provided in test results minus TESTOPTS portion)'".
- Enter the command "test1". All but one of the tests passes. That one test failure is due to missing content on the admin unlock request page.
- In your web browser, go to your app's home page. Click on "Login", then "Admin Login", and finally "Didn't receive unlock instructions?". The debug box shows that the "devise/unlocks" controller is in use.
- Replace the admin section of config/routes.rb with the following:
# BEGIN: admin
devise_for :admins,
controllers: { registrations: 'admins/registrations',
sessions: 'admins/sessions',
passwords: 'admins/passwords',
confirmations: 'admins/confirmations',
unlocks: 'admins/unlocks' }
# END: admin
- Refresh your web browser. The debug box should now show that the controller in use is "admins/unlocks".
- Replace the contents of app/views/admins/unlocks/new.html.erb with the following:
<% provide(:title, "Admin Unlock") %>
<h1>Admin Unlock</h1>
<%= form_for(resource, as: resource_name, url: unlock_path(resource_name), html: { method: :post }) do |f| %>
<%= devise_error_messages! %>
<div class="field">
<%= f.label :email %><br />
<%= f.email_field :email, autofocus: true %>
</div>
<div class="actions">
<%= f.submit "Resend unlock instructions" %>
</div>
<% end %>
<%= render "admins/shared/links" %>
- Enter the command "test1". All tests should now pass.
- Enter the command "sh git_check.sh". All tests should pass, and there should be no offenses.
- Enter the following commands:
git add .
git commit -m "Added admin locking capability"
- Enter the command "git push origin 09-13-admins_lock".
- Go to the GitHub repository and click on the "Compare and pull request" button for this branch.
- Accept this pull request to merge it with the master branch, but do NOT delete this branch.
- Enter the following commands:
git checkout master
git pull
sh heroku.sh