Browse Source

Remove #reset_otp_state hook (#91)

This feature was added so enable and unconfirmed mobile
phone number to be used for OTP purposes and have that
number removed at the start or end of a new session.

However, a simpler way do this would be to simply store
the unconfirmed mobile in the #user_session.  Indeed
that is what we are now doing in 18F identity project
which uses this gem:
https://github.com/18F/identity-idp/pull/220
master
Sam Clegg 9 years ago committed by Moncef Belyamani
parent
commit
60ce5f1e63
  1. 33
      README.md
  2. 23
      lib/two_factor_authentication/hooks/two_factor_authenticatable.rb
  3. 24
      spec/features/two_factor_authenticatable_spec.rb
  4. 9
      spec/rails_app/app/services/user_otp_sender.rb

33
README.md

@ -250,39 +250,6 @@ after them):
bundle exec rake db:rollback STEP=3
```
#### Executing some code after the user signs in and before they sign out
In some cases, you might want to perform some action right after the user signs
in, but before the OTP is sent, and also right before the user signs out. One
scenario where you would need this is if you are requiring users to confirm
their phone number first before they can receive an OTP. If they enter a wrong
number, then sign out or close the browser before they confirm, they won't be
able to confirm their real number. To solve this problem, we need to be able to
reset their unconfirmed number before they sign out or sign in, and before the
OTP code is sent.
To define this action, create a `#{user.class}OtpSender` class that takes the
current user as its parameter, and defines a `#reset_otp_state` instance method.
For example, if your user's class is `User`, you would create a `UserOtpSender`
class, like this:
```ruby
class UserOtpSender
def initialize(user)
@user = user
end
def reset_otp_state
if @user.unconfirmed_mobile.present?
@user.update(unconfirmed_mobile: nil)
end
end
end
```
If you have different types of users in your app (for example, User and Admin),
and you need different logic for each type of user, create a second class for
your admin user, such as `AdminOtpSender`, with its own logic for
`#reset_otp_state`.
### Example App
[TwoFactorAuthenticationExample](https://github.com/Houdini/TwoFactorAuthenticationExample)

23
lib/two_factor_authentication/hooks/two_factor_authenticatable.rb

@ -1,6 +1,4 @@
Warden::Manager.after_authentication do |user, auth, options|
reset_otp_state_for(user)
if auth.env["action_dispatch.cookies"]
expected_cookie_value = "#{user.class}-#{user.id}"
actual_cookie_value = auth.env["action_dispatch.cookies"].signed[TwoFactorAuthentication::REMEMBER_TFA_COOKIE_NAME]
@ -13,24 +11,3 @@ Warden::Manager.after_authentication do |user, auth, options|
end
end
end
Warden::Manager.before_logout do |user, _auth, _options|
reset_otp_state_for(user)
end
def reset_otp_state_for(user)
klass_string = "#{user.class}OtpSender"
klass = class_from_string(klass_string)
return unless klass
otp_sender = klass.new(user)
otp_sender.reset_otp_state if otp_sender.respond_to?(:reset_otp_state)
end
def class_from_string(string)
string.constantize
rescue NameError
false
end

24
spec/features/two_factor_authenticatable_spec.rb

@ -187,25 +187,14 @@ feature "User of two factor authentication" do
let(:user) { create_user }
let(:admin) { create_admin }
scenario 'when UserOtpSender#reset_otp_state is defined' do
scenario 'user signs is' do
visit new_user_session_path
complete_sign_in_form_for(user)
expect(user.reload.email).to eq 'updated@example.com'
end
scenario 'when UserOtpSender#reset_otp_state is not defined' do
otp_sender = instance_double(UserOtpSender)
allow(otp_sender).to receive(:respond_to?).with(:reset_otp_state).and_return(false)
expect(UserOtpSender).to receive(:new).with(user).and_return(otp_sender)
expect(otp_sender).to_not receive(:reset_otp_state)
visit new_user_session_path
complete_sign_in_form_for(user)
expect(page).to have_content('Signed in successfully.')
end
scenario 'when AdminOtpSender is not defined' do
scenario 'admin signs in' do
visit new_admin_session_path
complete_sign_in_form_for(admin)
@ -217,16 +206,15 @@ feature "User of two factor authentication" do
let(:user) { create_user }
let(:admin) { create_admin }
scenario 'when UserOtpSender#reset_otp_state is defined' do
scenario 'user signs out' do
visit new_user_session_path
complete_sign_in_form_for(user)
user.update_attributes(email: 'foo@example.com')
visit destroy_user_session_path
expect(user.reload.email).to eq 'updated@example.com'
expect(page).to have_content('Signed out successfully.')
end
scenario 'when AdminOtpSender is not defined' do
scenario 'admin signs out' do
visit new_admin_session_path
complete_sign_in_form_for(admin)
visit destroy_admin_session_path

9
spec/rails_app/app/services/user_otp_sender.rb

@ -1,9 +0,0 @@
class UserOtpSender
def initialize(user)
@user = user
end
def reset_otp_state
@user.update_attributes(email: 'updated@example.com')
end
end
Loading…
Cancel
Save