Git Product home page Git Product logo

devise-two-factor's Issues

When using lockable, failed_attempts is incremented by two after failed login attempt

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

Demo throws error

Fresh install of the demo app.

Clicking "Enable 2FA" here...
enable-2fa-page

...throws an error page:
error-2fa-page

README mentions generating an encryption key but doesn't mention where to put it or what to call it.

Rails 5/Devise 4 deprecations

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.

NoMethodError: undefined method `otp_backup_codes'

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.

Two factor as second login step?

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?

Allow attr_encrypted 2.x

attr_encrypted 2.0 introduced more secure default settings (aes-256-gcm) and a new mode per_attribute_iv

Previously consumed OTP is considered valid after drift period has passed

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

Should probably mention that it's using TOTP

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.

NoMethodError: undefined method `validate_and_consume_otp!'

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:

  • Bundled gem 'devise-two-factor' and gem 'rqrcode_png'.
  • Updated the database User structure with the 5 new fields.
  • Defined the ENV['VARIABLE']
  • Updated User model accordingly
class User < ActiveRecord::Base
  devise :rememberable, :trackable, :lockable,
         :session_limitable, :two_factor_authenticatable,
         :otp_secret_encryption_key => ENV['VARIABLE']
  # ...
end
  • Created the views
  • Updated devise views
  • Updated routes
  • Whitelisted application params
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.

NoMethodError: undefined method `validate_and_consume_otp!'

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>

Add a CHANGELOG

Can we get a CHANGELOG file for the gem? Would be nice to have for seeing what's changed between releases.

ROTP 3.x support

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]

Upgrade guide for devise-two-factor with attr_encrypted 3.x doesn't work

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.

Backup codes + mysql

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.

Disallow authentication code once verified

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.

How to check user is two-factor-authenticated or not ?

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?

Login using backup codes

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

Can't generate Otp_secret (ArgumentError: must specify a :key)

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)

several tests in shared example group fail

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

3 errors that looks like an issue with attr_encrypted version

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?

Change value of otp_allowed_drift

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.

Authentication code error message

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'?

Update to latest version of rotp

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:

  1. Devise::Models::TwoFactorAuthenticatable When included in a class behaves like two_factor_authenticatable #otp_provisioning_uri should return uri with issuer option
    Failure/Error: subject.otp_provisioning_uri(account, issuer: issuer).should match(%r{otpauth://totp/#{account}?issuer=#{issuer}&secret=\w{#{otp_secret_length}}$})
    expected "otpauth://totp/[email protected]?secret=5q5cxn5m5xsg7qdkhi3ga6zfmfdngeah7muhnz2sx2bcpgfxp2aqm5cp4ieeakn5ja3xzlu35n5r7rtbum3zy2bsenlpynzeryw5ecktzwbsxt5ba74yy6og6umv5f55&issuer=Tinfoil" to match /otpauth://totp/[email protected]?issuer=Tinfoil&secret=\w{128}$/
    Diff:
    @@ -1,2 +1,2 @@
    -/otpauth://totp/[email protected]?issuer=Tinfoil&secret=\w{128}$/
    +"otpauth://totp/[email protected]?secret=5q5cxn5m5xsg7qdkhi3ga6zfmfdngeah7muhnz2sx2bcpgfxp2aqm5cp4ieeakn5ja3xzlu35n5r7rtbum3zy2bsenlpynzeryw5ecktzwbsxt5ba74yy6og6umv5f55&issuer=Tinfoil"

Shared Example Group: "two_factor_authenticatable" called from ./spec/devise/models/two_factor_authenticatable_spec.rb:14

./lib/devise_two_factor/spec_helpers/two_factor_authenticatable_shared_examples.rb:73:in `block (3 levels) in <top (required)>'

Release 3.0.0 on RubyGems

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?

Doesn't work with Devise >= 3.5

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

assets:precompile failing when there is no DB connection

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)

Demo not working

Getting undefined method 'for' for #<Devise::ParameterSanitizer:0x007fbfb5a59ed0>
in
app/controllers/application_controller.rb:11:in 'configure_permitted_parameters'

Support NoSQL databases in generator

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.

OTP attempt param blocked by Devise

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.

TwoFactorBackupable not working?

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?

undefined method `bcrypt' for Devise:Module

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?_

Symmetrically encrypt backup codes with user password & attr_encrypted

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?

How should I integrate Devise two factor authentication with custom sessions controller?

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?

How to enable using backup codes

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.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.