devise-two-factor / devise-two-factor Goto Github PK
View Code? Open in Web Editor NEWBarebones two-factor authentication with Devise
License: MIT License
Barebones two-factor authentication with Devise
License: MIT License
When using devise-two-factor with devise lockable, there are somehow two calls being made to validate/valid_for_authentication? - the latter of which is doing the failed_attempts increment.
The first failed_attempts increment happens within this block, and the latter seems to be happening after the authenticate! method is finished executing.
if validate(resource) { !resource.otp_required_for_login ||
resource.valid_otp?(params[scope]['otp_attempt']) }
super
end
My devise initializer is configuring the warden strategy as follows:
config.warden do |manager|
manager.default_strategies(:scope => :user).unshift :two_factor_authenticatable
end
My user model is set up with devise as follows:
devise :two_factor_authenticatable, :otp_secret_encryption_key => ENV['RSA_KEY_PW'], otp_secret_length: 64
devise :registerable, :recoverable, :invitable, :trackable, :timeoutable, :lockable
Provide warning/guidance for the yanked version of attr_encrypted.
These occur when we run our test suite with Rails 5.0.0.beta2, Devise 4.0.0.rc1, and a fork of devise-two-factor that allows Devise 4 in the gemspec:
DEPRECATION WARNING: alias_method_chain is deprecated. Please, use Module#prepend instead. From module, you can access the original method using super. (called from <top (required)> at /home/ubuntu/ImageHex/vendor/bundle/ruby/2.3.0/bundler/gems/devise-two-factor-0fa0a6914739/lib/devise_two_factor/models/two_factor_authenticatable.rb:1)
DEPRECATION WARNING: alias_method_chain is deprecated. Please, use Module#prepend instead. From module, you can access the original method using super. (called from <top (required)> at /home/ubuntu/ImageHex/vendor/bundle/ruby/2.3.0/bundler/gems/devise-two-factor-0fa0a6914739/lib/devise_two_factor/models/two_factor_authenticatable.rb:1)
DEPRECATION WARNING: alias_method_chain is deprecated. Please, use Module#prepend instead. From module, you can access the original method using super. (called from <top (required)> at /home/ubuntu/ImageHex/vendor/bundle/ruby/2.3.0/bundler/gems/devise-two-factor-0fa0a6914739/lib/devise_two_factor/models/two_factor_authenticatable.rb:1)
DEPRECATION WARNING: alias_method_chain is deprecated. Please, use Module#prepend instead. From module, you can access the original method using super. (called from <top (required)> at /home/ubuntu/ImageHex/vendor/bundle/ruby/2.3.0/bundler/gems/devise-two-factor-0fa0a6914739/lib/devise_two_factor/models/two_factor_authenticatable.rb:1)
Command used is bundle exec rspec --color --require spec_helper --require rails_helper --format documentation spec
on Circle CI. Can provide more information if needed.
I've just installed this gem and this is the error I get on log in:
NoMethodError in Devise::SessionsController#create
undefined method `otp_backup_codes' for #<User:0xd55b920>
I added Backup Codes.
I also have not called any specific methods yet.
From #18. We should look into separating the bcrypt functionality into a helper (as mentioned on https://github.com/tinfoil/devise-two-factor/blob/75d9ce56b8b39c8257d0d3729f8cc64bcf824f66/lib/devise_two_factor/models/two_factor_backupable.rb#L42)
In most cases where I've used Two-Factor Auth the auth code is a second login step.
Are they any good examples anywhere on how to make this a two step process?
You've got to support devise 3.5+ for sign_in_after_reset_password to be available. Right now the docs are telling you to do something that doesn't work.
Do you follow Semantic Versioning http://semver.org? If yes, can this be mentioned in README? If not, can you consider it?
attr_encrypted 2.0 introduced more secure default settings (aes-256-gcm) and a new mode per_attribute_iv
Releated to #20. Once heartcombo/devise#3467 is cut into a release we should update the README to advocate for the newly-provided configuration option.
RFC 6238 says that once an OTP is used, it cannot ever be used again.
The tests here are not properly testing the scenario where an OTP is consumed, then the user waits an amount between the drift period and twice the drift period, then tries entering the OTP again. The expected behavior is that the OTP should not be valid, but it is.
The problem with the tests is that they are freezing Time.current
, but because current_otp_timestep
depends on the current time, it must not be frozen. Instead Timecop.travel
must be used to advance in time.
Here is a failing spec:
describe '#validate_and_consume_otp!' do
let(:otp_secret) { '2z6hxkdwi3uvrnpn' }
before :each do
subject.otp_secret = otp_secret
end
after :each do
Timecop.return
end
context 'with a stored consumed_timestep' do
context 'given a previously correct OTP' do
it 'fails to validate' do
consumed_otp = ROTP::TOTP.new(otp_secret).at(Time.now)
subject.validate_and_consume_otp!(consumed_otp)
amount_to_travel = (subject.class.otp_allowed_drift).seconds
Timecop.travel(amount_to_travel)
expect(subject.validate_and_consume_otp!(consumed_otp)).to be false
end
end
end
end
Perhaps via the demo app?
I was curious and tried finding out what kind of OTP scheme you were using. Dug through the dependencies (rotp) and noticed it supported both HOTP & TOTP, which you use TOTP though.
Makes sense, and is much easier conceptually. I figure it should be mentioned in the README.
I'm trying to setup this but I think it isnt being initializated.
I followed everything in this tutorial, what am I missing?
https://github.com/mikamai/rails-2fact-auth-example
I have:
class User < ActiveRecord::Base
devise :rememberable, :trackable, :lockable,
:session_limitable, :two_factor_authenticatable,
:otp_secret_encryption_key => ENV['VARIABLE']
# ...
end
def configure_permitted_parameters
devise_parameter_sanitizer.for(:sign_in) << :otp_attempt
end
Updated again User.rb model
def activate_two_factor params
otp_params = { otp_secret: unconfirmed_otp_secret }
if !valid_password?(params[:password])
errors.add :password, :invalid
false
elsif !validate_and_consume_otp!(params[:otp_attempt], otp_params)
errors.add :otp_attempt, :invalid
false
else
activate_two_factor!
end
end
def deactivate_two_factor params
if !valid_password?(params[:password])
errors.add :password, :invalid
false
else
self.otp_required_for_login = false
self.otp_secret = nil
save
end
end
private
def activate_two_factor!
self.otp_required_for_login = true
self.otp_secret = current_user.unconfirmed_otp_secret
self.unconfirmed_otp_secret = nil
save
end
Created the two_factors_controller.rb
class TwoFactorsController < ApplicationController
before_filter :authenticate_user!
def new
end
# If user has already enabled the two-factor auth, we generate a
# temp. otp_secret and show the 'new' template.
# Otherwise we show the 'show' template which will allow the user to disable
# the two-factor auth
def show
unless current_user.otp_required_for_login?
current_user.unconfirmed_otp_secret = User.generate_otp_secret
current_user.save!
@qr = RQRCode::QRCode.new(two_factor_otp_url).to_img.resize(240, 240).to_data_url
render 'new'
end
end
# User#activate_two_factor will return a boolean. When false is returned
# we presume the model has some errors.
def create
permitted_params = params.require(:user).permit :password, :otp_attempt
if current_user.activate_two_factor permitted_params
redirect_to root_path, notice: "You have enabled Two Factor Auth"
else
render 'new'
end
end
# If the provided password is correct, two-factor is disabled
def destroy
permitted_params = params.require(:user).permit :password
if current_user.deactivate_two_factor permitted_params
redirect_to root_path, notice: "You have disabled Two Factor Auth"
else
render 'show'
end
end
private
# The url needed to generate the QRCode so it can be acquired by
# Google Authenticator
def two_factor_otp_url
"otpauth://totp/%{app_id}?secret=%{secret}&issuer=%{app}" % {
:secret => current_user.unconfirmed_otp_secret,
:app => "",
:app_id => "#{current_user.username}"
}
end
end
Everything seems to be working, but when I go to /two_factor and click the button I get error from User model.
So it looks like there was a security update with a breaking change which caused 3.0 to be released: attr-encrypted/attr_encrypted@5834ef4
Should probably update to that.
Hi,
Can you take a look at https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=798466 ?
class User < ActiveRecord::Base
devise :rememberable, :trackable, :lockable,
:session_limitable, :two_factor_authenticatable,
:otp_secret_encryption_key => ENV['TWO_FACTOR_SECRET']
# ...
end
and then
2.1.1 :001 >user = user.first
2.1.1 :002 > user.validate_and_consume_otp!('x','x')
NoMethodError: undefined method `validate_and_consume_otp!' for #<User:0x00000006402378>
Can we get a CHANGELOG file for the gem? Would be nice to have for seeing what's changed between releases.
Hello! Gem will be support ROTP 3.x ?
Reason for this issue: provisioning uri have new format in 3.x versions and clients which use Microsoft authenticator - don't see issuer.
Link: [https://github.com/mdp/rotp/blob/master/lib/rotp/totp.rb#L55-L68]
Assuming the user has followed the README.md
instructions for past versions of devise-two-factor, they should have something like this in their User model:
devise :two_factor_authenticatable,
:otp_secret_encryption_key => ENV['YOUR_ENCRYPTION_KEY_HERE']
The suggestion in the UPGRADING.md
is to replace the above with the following:
attr_encrypted :otp_secret,
:key => self.otp_secret_encryption_key,
:mode => :per_attribute_iv_and_salt,
:algorithm => 'aes-256-cbc'
devise :two_factor_authenticatable,
:otp_secret_encryption_key => ENV['DEVISE_TWO_FACTOR_ENCRYPTION_KEY']
The problem with this is that otp_secret_encryption_key
isn't an attribute of the model, so it throws an error.
I had to change the code to the following for it to work with devise-two-factor (current devise-4
branch), Devise 4, and attr_encrypted/encryptor 3.0:
attr_encrypted :otp_secret,
:key => ENV['DEVISE_TWO_FACTOR_ENCRYPTION_KEY'],
:mode => :per_attribute_iv_and_salt,
:algorithm => 'aes-256-cbc'
devise :two_factor_authenticatable,
:otp_secret_encryption_key => ENV['DEVISE_TWO_FACTOR_ENCRYPTION_KEY']
The error was initially:
NoMethodError - undefined method `otp_secret_encryption_key' for #<Class:0x007fd612c5d880>:
The error I got after changing self.otp_secret_encryption_key
to :otp_secret_encryption_key
was:
NoMethodError - undefined method `bytesize' for :otp_secret_encryption_key:Symbol:
After adding :insecure_mode => true
it became:
TypeError - no implicit conversion of Symbol into String:
Only when I used the environment variable directly did it work. I should also note that we don't actually use an environment variable, but instead use File.read(Rails.root.join('.secret')).chomp
. I don't think that changes anything, but I thought it was worth mentioning just in case.
Just a note that in it's current form, using backup codes with the mysql db driver won't work, as mysql doesn't support the array data type. Rails will save the codes w/o issue, but the code fails when trying to read the field as it is a serialized YAML string. I had to use this in my User model to make it work:
def otp_backup_codes
codes = self.read_attribute(:otp_backup_codes)
codes = YAML::load(codes) unless codes.kind_of?(Array) || codes.nil?
codes
end
Additionally, Devise has moved their Devise.bcrypt definition into the database_authenticatable module, so I had to use a monkey-patch to define it myself.
This is a suggestion for small improvement. RFC 6238 requires the implementation to disallow (MUST NOT) multiple submissions of the same authentication code. This is apparently to detect MITM and over the shoulder attacks.
I need to to authenticate a user is two-step authenticated or not.
As in simple devise we had a method like
authenticate_user!
I need to set this in before_action filter.
Can we have similar method for two-factor-authentication?
It has a section on enabling two-factor authentication, but not on disabling it.
I had a number of issues when trying to implement disabling 2FA.
Hello,
While I've got the regular two-factor authentication flow using FreeOTP/Google Authenticator working in my app (which was a breeze, thanks to this awesome gem & documentation!), I'm not able to get the login flow using two-factor backup codes working.
I can see from the app logs that the backup code entered in the otp_attempt
form field has been consumed... its removed from the otp_backup_codes
model attribute through an SQL update. But unfortunately, the login doesn't succeed. The user is returned back to the login screen with a 401 Unauthorized
response code from the app.
I couldn't find any resources through a google search that could've provided some insight on such a problem existing, so I'm assuming this has to be a problem with my app... I'd much appreciate it if someone can give me some pointers/directions on how I can debug this problem.
Thanks in advance!
Dhwanit
See: https://travis-ci.org/tinfoil/devise-two-factor/jobs/149565884
This can be fixed in a few ways:
Hello and first of all thanks for this awesome gem!
I want to add it to my admin system, but faced with some troubles. My :two_factor_authenticatable
named AdminUser
, so I followed all prescriptions you have in the readme: run generator, migration etc and now trying to make 2 factor actually work with.
u = AdminUser.first
u.otp_secret = AdminUser.generate_otp_secret
With this I have an error:
ArgumentError: must specify a :key
from /home/vagrant/.rvm/gems/ruby-2.2.2/gems/encryptor-1.3.0/lib/encryptor.rb:51:in `crypt'
I'm on Devise (3.5.2) and devise-two-factor (1.1.0)
uri's have parameters in a reverse order. spec should be more accepting of that.
1) User behaves like two_factor_authenticatable #otp_provisioning_uri should return uri with issuer option
Failure/Error: expect(subject.otp_provisioning_uri(account, issuer: issuer)).to match(%r{otpauth://totp/#{account}\?secret=\w{#{otp_secret_length}}&issuer=#{issuer}$})
expected "otpauth://totp/[email protected]?issuer=Tinfoil&secret=ydvy642tugtmdw6tn4p3e7lkacmut6chqy6u4o3a6co55rhu4eip2ls2kd6cw2tcll6espnxtabak6xyjypn6b7zg5a7huplbq4vpgobyhi5gcnc5oyrpwxv6k73is4n" to match /otpauth:\/\/totp\/[email protected]\?secret=\w{128}&issuer=Tinfoil$/
Diff:
@@ -1,2 +1,2 @@
-/otpauth:\/\/totp\/[email protected]\?secret=\w{128}&issuer=Tinfoil$/
+"otpauth://totp/[email protected]?issuer=Tinfoil&secret=ydvy642tugtmdw6tn4p3e7lkacmut6chqy6u4o3a6co55rhu4eip2ls2kd6cw2tcll6espnxtabak6xyjypn6b7zg5a7huplbq4vpgobyhi5gcnc5oyrpwxv6k73is4n"
2) User behaves like two_factor_authenticatable #validate_and_consume_otp! validates an OTP within the allowed drift
Failure/Error: expect(subject.validate_and_consume_otp!(otp)).to be true
NoMethodError:
undefined method `default_otp_required_for_login' for nil:NilClass
I get these 3 test failures with devise 3.5 and 4.0. attr_encrypted is 1.3.4.
Failures:
1) Devise::Models::TwoFactorAuthenticatable When included in a class otp_secret options should be of the mode
Failure/Error: expect(subject.encrypted_attributes[:otp_secret][:algorithm]).to eq('aes-256-cbc')
NoMethodError:
undefined method `encrypted_attributes' for #<TwoFactorAuthenticatableWithCustomizeAttrEncryptedDouble:0x00000003ab8760>
Did you mean? encrypted_otp_secret_salt=
# ./spec/devise/models/two_factor_authenticatable_spec.rb:75:in `block (4 levels) in <top (required)>'
2) Devise::Models::TwoFactorAuthenticatable When included in a class otp_secret options should be of the key
Failure/Error: expect(subject.encrypted_attributes[:otp_secret][:key]).to eq('test-key'*8)
NoMethodError:
undefined method `encrypted_attributes' for #<TwoFactorAuthenticatableWithCustomizeAttrEncryptedDouble:0x00000004122178>
Did you mean? encrypted_otp_secret_salt=
# ./spec/devise/models/two_factor_authenticatable_spec.rb:67:in `block (4 levels) in <top (required)>'
3) Devise::Models::TwoFactorAuthenticatable When included in a class otp_secret options should be of the mode
Failure/Error: expect(subject.encrypted_attributes[:otp_secret][:mode]).to eq(:per_attribute_iv_and_salt)
NoMethodError:
undefined method `encrypted_attributes' for #<TwoFactorAuthenticatableWithCustomizeAttrEncryptedDouble:0x00000004120148>
Did you mean? encrypted_otp_secret_salt=
# ./spec/devise/models/two_factor_authenticatable_spec.rb:71:in `block (4 levels) in <top (required)>'
Finished in 19.4 seconds (files took 12.06 seconds to load)
41 examples, 3 failures
Failed examples:
rspec ./spec/devise/models/two_factor_authenticatable_spec.rb:74 # Devise::Models::TwoFactorAuthenticatable When included in a class otp_secret options should be of the mode
rspec ./spec/devise/models/two_factor_authenticatable_spec.rb:66 # Devise::Models::TwoFactorAuthenticatable When included in a class otp_secret options should be of the key
rspec ./spec/devise/models/two_factor_authenticatable_spec.rb:70 # Devise::Models::TwoFactorAuthenticatable When included in a class otp_secret options should be of the mode
Randomized with seed 39654
/usr/bin/ruby2.3 /usr/bin/rspec --pattern ./spec/\*\*/\*_spec.rb --format documentation failed
ERROR: Test "ruby2.3" failed. Exiting.
@connorshea do I need to update attr_encrypted?
Hi! I'm trying to change the value of otp_allowed_drift
, but have no success with that. Could you please help me here?
What I've tried already:
# config/initializers/devise.rb
Devise.setup do |config|
config.otp_allowed_drift = 1800
end
and
# config/initializers/devise.rb
Devise.otp_allowed_drift = 1800
Devise.setup do |config|
...
end
With the second attempt the value of otp_allowed_drift
had been changed, but my otp codes still changes like once in 30 seconds (default value), not once in 30 minutes as I expect to.
If user got a authentication code error, the error message is still 'Invalid email or password.', how to specify the message to some sentence like 'Authentication code is wrong'?
Hi,
I am packaging devise-two-factor for Debian, as part of GitLab packaging. Debian has rotp version 2.1.1 in the archives and it gives the following test failure with devise-two-factor. Can you please update the dependency of rotp to the latest version? It would be a great help. Thanks.
.F...................
Failures:
Shared Example Group: "two_factor_authenticatable" called from ./spec/devise/models/two_factor_authenticatable_spec.rb:14
Not to be a bother, but I'd like to upgrade GitLab to Devise 4, and this is the only thing blocking that upgrade.
Is there anything left to do or is it ready for release?
Currently devise-two-factor.gemspec
depends on Devise 3.5.x. Devise 4.0, while unreleased right now, will be required for use with Rails 5. Something to note.
Is it actually incompatible or just the dependencies are set that way?
Bundler could not find compatible versions for gem "devise":
In snapshot (Gemfile.lock):
devise (= 3.5.1)
In Gemfile:
devise-two-factor (~> 1.0.2) ruby depends on
devise (< 3.5, >= 3.2.4) ruby
When devise-two-factor is enabled, rake assets:precompile
tries to connect to the DB. The problem is related to devise that causes the model to be loaded and attr_encrypted that require DB connection on class load.
rake aborted!
ActiveRecord::NoDatabaseError: FATAL: database "example_test" does not exist
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activerecord-4.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:661:in `rescue in connect'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activerecord-4.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:651:in `connect'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activerecord-4.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:242:in `initialize'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activerecord-4.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:44:in `new'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activerecord-4.2.2/lib/active_record/connection_adapters/postgresql_adapter.rb:44:in `postgresql_connection'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activerecord-4.2.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:438:in `new_connection'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activerecord-4.2.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:448:in `checkout_new_connection'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activerecord-4.2.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:422:in `acquire_connection'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activerecord-4.2.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:349:in `block in checkout'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activerecord-4.2.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:348:in `checkout'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activerecord-4.2.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:263:in `block in connection'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activerecord-4.2.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:262:in `connection'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activerecord-4.2.2/lib/active_record/connection_adapters/abstract/connection_pool.rb:567:in `retrieve_connection'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activerecord-4.2.2/lib/active_record/connection_handling.rb:113:in `retrieve_connection'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activerecord-4.2.2/lib/active_record/connection_handling.rb:87:in `connection'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activerecord-4.2.2/lib/active_record/model_schema.rb:230:in `table_exists?'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/attr_encrypted-1.3.4/lib/attr_encrypted/adapters/active_record.rb:59:in `attribute_instance_methods_as_symbols'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/attr_encrypted-1.3.4/lib/attr_encrypted.rb:130:in `block in attr_encrypted'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/attr_encrypted-1.3.4/lib/attr_encrypted.rb:125:in `each'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/attr_encrypted-1.3.4/lib/attr_encrypted.rb:125:in `attr_encrypted'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/attr_encrypted-1.3.4/lib/attr_encrypted/adapters/active_record.rb:51:in `attr_encrypted'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-two-factor-2.0.0/lib/devise_two_factor/models/two_factor_authenticatable.rb:11:in `block in <module:TwoFactorAuthenticatable>'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/concern.rb:120:in `class_eval'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/concern.rb:120:in `append_features'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise/models.rb:103:in `include'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise/models.rb:103:in `block (2 levels) in devise'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise/models.rb:87:in `each'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise/models.rb:87:in `block in devise'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise/models.rb:114:in `devise_modules_hook!'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise/models.rb:84:in `devise'
/Users/gawaine/dev/example_app/app/models/admin_user.rb:10:in `<class:AdminUser>'
/Users/gawaine/dev/example_app/app/models/admin_user.rb:9:in `<top (required)>'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:274:in `require'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:274:in `block in require'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:240:in `load_dependency'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:274:in `require'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:360:in `require_or_load'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:494:in `load_missing_constant'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:184:in `const_missing'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/inflector/methods.rb:261:in `const_get'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/inflector/methods.rb:261:in `block in constantize'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/inflector/methods.rb:259:in `each'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/inflector/methods.rb:259:in `inject'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/inflector/methods.rb:259:in `constantize'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:566:in `get'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:597:in `constantize'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise.rb:287:in `get'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise/mapping.rb:81:in `to'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise/mapping.rb:76:in `modules'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise/mapping.rb:93:in `routes'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise/mapping.rb:160:in `default_used_route'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise/mapping.rb:70:in `initialize'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise.rb:321:in `new'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise.rb:321:in `add_mapping'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise/rails/routes.rb:224:in `block in devise_for'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise/rails/routes.rb:223:in `each'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/devise-3.5.2/lib/devise/rails/routes.rb:223:in `devise_for'
/Users/gawaine/dev/example_app/config/routes.rb:23:in `block (3 levels) in <top (required)>'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/actionpack-4.2.2/lib/action_dispatch/routing/mapper.rb:940:in `block in constraints'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/actionpack-4.2.2/lib/action_dispatch/routing/mapper.rb:816:in `scope'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/actionpack-4.2.2/lib/action_dispatch/routing/mapper.rb:940:in `constraints'
/Users/gawaine/dev/example_app/config/routes.rb:22:in `block (2 levels) in <top (required)>'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/actionpack-4.2.2/lib/action_dispatch/routing/mapper.rb:940:in `block in constraints'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/actionpack-4.2.2/lib/action_dispatch/routing/mapper.rb:816:in `scope'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/actionpack-4.2.2/lib/action_dispatch/routing/mapper.rb:940:in `constraints'
/Users/gawaine/dev/example_app/config/routes.rb:21:in `block in <top (required)>'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/actionpack-4.2.2/lib/action_dispatch/routing/route_set.rb:432:in `instance_exec'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/actionpack-4.2.2/lib/action_dispatch/routing/route_set.rb:432:in `eval_block'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/actionpack-4.2.2/lib/action_dispatch/routing/route_set.rb:410:in `draw'
/Users/gawaine/dev/example_app/config/routes.rb:5:in `<top (required)>'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:268:in `load'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:268:in `block in load'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:240:in `load_dependency'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:268:in `load'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/application/routes_reloader.rb:40:in `block in load_paths'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/application/routes_reloader.rb:40:in `each'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/application/routes_reloader.rb:40:in `load_paths'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/application/routes_reloader.rb:16:in `reload!'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/application/routes_reloader.rb:26:in `block in updater'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/file_update_checker.rb:75:in `call'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/file_update_checker.rb:75:in `execute'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/application/routes_reloader.rb:27:in `updater'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/application/routes_reloader.rb:7:in `execute_if_updated'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/application/finisher.rb:69:in `block in <module:Finisher>'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/initializable.rb:30:in `instance_exec'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/initializable.rb:30:in `run'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/initializable.rb:55:in `block in run_initializers'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/initializable.rb:54:in `run_initializers'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/application.rb:352:in `initialize!'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/railtie.rb:194:in `public_send'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/railtie.rb:194:in `method_missing'
/Users/gawaine/dev/example_app/config/environment.rb:5:in `<top (required)>'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:274:in `require'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:274:in `block in require'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:240:in `load_dependency'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/activesupport-4.2.2/lib/active_support/dependencies.rb:274:in `require'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/application.rb:328:in `require_environment!'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/railties-4.2.2/lib/rails/application.rb:457:in `block in run_tasks_blocks'
/Users/gawaine/.rvm/gems/ruby-2.2.2/gems/sprockets-rails-2.3.1/lib/sprockets/rails/task.rb:64:in `block (2 levels) in define'
/Users/gawaine/.rvm/gems/ruby-2.2.2/bin/ruby_executable_hooks:15:in `eval'
/Users/gawaine/.rvm/gems/ruby-2.2.2/bin/ruby_executable_hooks:15:in `<main>'
Tasks: TOP => environment
(See full trace by running task with --trace)
This is what Slack, Stripe, and others do to prevent other people with access to your computer from disabling Two-Factor Auth on your account. I realize it's not likely to stop people if they have physical access, but why not add it?
Getting undefined method 'for' for #<Devise::ParameterSanitizer:0x007fbfb5a59ed0>
in
app/controllers/application_controller.rb:11:in 'configure_permitted_parameters'
It would be awesome if, in the generator, you could specify an optional arg that let you generate for a NoSQL database (like Mongoid). So instead of creating a database migration, it would just add the appropriate fields to the model file.
Devise 4.0 was released last week: https://rubygems.org/gems/devise/versions/4.0.0
Probably worth upgrading now.
Ran into this issue while implementing my app's login flow.
Devise rejects legitimate log-in attempts because otp_attempt
is not whitelisted:
Processing by Devise::SessionsController#new as HTML
Parameters: {"utf8"=>"โ", "authenticity_token"=>"he0idQUk10utMP56rfV/NKDujXoQywecAUpurtX3so4=", "user"=>{"email"=>"[email protected]", "password"=>"[FILTERED]", "otp_attempt"=>"1234"}, "commit"=>"Log in"}
Unpermitted parameters: otp_attempt
Solved by adding a little code to application_controller.rb
(h/t Stack Overflow):
before_filter :update_sanitized_params, if: :devise_controller?
def update_sanitized_params
devise_parameter_sanitizer.for(:sign_in) do |u|
u.permit(:otp_attempt, :email, :password)
end
end
Can this gem update the default whitelisted attributes to allow otp_attempt
? Thoughts on the best ways to implement?
In the meantime, can add this problem/solution into the README.
I'm getting the following error when I try to generate the 2FA backup codes: undefined method 'generate_otp_backup_codes' for #<Class:0x007fe485bbbf90>
The code looks like this:
def enable_twofactor
self.otp_secret = User.generate_otp_secret
self.otp_backup_codes = User.generate_otp_backup_codes
self.save
end
Generating the otp_secret
works, but not the backup codes. I've added the db migration and run rake db:migrate
, added the strategy to the devise initializer, followed the instructions and re-read them over and over.
Any ideas as to why this might be happening?
Help!
I use this gem in my project. but I face the error when generate backup codes.
My devise is 3.1.0 and this gem is locking 1.0.0
I find the Device.bcrypt method is defined in module database_authenticate which is conflict with two_factor_authenticatable.
Since some reason, I cannot upgrade my devise.
_So how can I use two_factor_authenticatable and two_factor_backupable with devise 3.1.0?_
I've seen a lot of vendors use the pattern of re-displaying the users' backup codes many times (usually after user re-enters their password for verification purposes). And even showing which codes have been burned. Even Google has adopted this pattern.
Unless I'm mistaken, because TwoFactorBackupable uses Devise::Encryptor#digest
the codes can only be displayed once and no more. While this is wonderfully secure, I feel like the hit to the user is such that it warrants re-evaluation.
I propose that attr_encrypted
is leveraged to safely keep the backup codes encrypted at rest but can be, when combined with a supplied password, be displayed the user on subsequent requests in case they need to reprint or rewrite them down.
attr_encrypted
supports methods as a key so associating it with a user's password is doable.
What do you think?
#27 is back from the dead with validate_and_consume_otp! nil
Affected version 2.0.1
I integrated the Houdini two factor authentication with existing rails application.
First I doesn't have any custom sessions_controller then the two_factor_authentication is working fine.
But whereas I written custom create action in Sessions Controller then it doesn't authenticated by two_factor_authentication.
Here is the custom code for create action of Sessions Controller.
if status_response.nil?
render :file => 'public/api_not_found.html', :status => :not_found, :layout => false
else
if status_response['code'].to_i == 1
signed_out = (Devise.sign_out_all_scopes ? sign_out : sign_out(resource_name))
flash[:alert] = 'Invalid Email ID or password.'
yield if block_given?
respond_to_on_destroy
else
self.resource = warden.authenticate!(auth_options)
set_flash_message(:notice, :signed_in) if is_flashing_format?
sign_in(resource_name, resource)
yield resource if block_given?
respond_with resource, location: after_sign_in_path_for(resource)
end
end
Model code of user.rb:
devise :two_factor_authenticatable, :database_authenticatable, :registerable,
:recoverable, :rememberable, :trackable, :validatable,
:confirmable, password_length: 8..30
has_one_time_password
def send_two_factor_authentication_code
puts ">>>>>>>>>>>>>>> otp_secret_key: #{otp_secret_key}, otp_code: #{otp_code}"
end
I know if we are customizing the create action of Sessions Controller then we should call the two_factor_authentication. I tried to invoke this in controller but it throws an error.
So my question how should i integrate the two_factor_authentication with custom create action of Session Controller?
Should it be a separate page from the Authentication Code input page, or should the Authentication Code input page support backup codes? If the latter is what's intended, it isn't working for me. The README doesn't specify how we're supposed to do that.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.