Code Monkey home page Code Monkey logo

google-authenticator's Introduction

GoogleAuthenticatorRails

Gem Version Code Climate Test Coverage CircleCI

Rails (ActiveRecord) integration with the Google Authenticator apps for Android and the iPhone. Uses the Authlogic style for cookie management.

Installation

Add this line to your application's Gemfile:

gem 'google-authenticator-rails'

And then execute:

$ bundle

Or install it yourself as:

$ gem install google-authenticator-rails

Usage

Example:

class User
  acts_as_google_authenticated
end

@user = User.new
@user.set_google_secret           # => true
@user.google_secret_value         # => 16-character plain-text secret, whatever the name of the secret column
@user.google_qr_uri               # => http://path.to.chart/qr?with=params
@user.google_authentic?(123456)   # => true
@user.clear_google_secret!        # => true
@user.google_secret_value         # => nil

Google Labels

When setting up an account with GoogleAuthenticatorRails you need to provide a label for that account (to distinguish it from other accounts).

GoogleAuthenticatorRails allows you to customize how the record will create that label. There are three options:

  • The default just uses the column email on the model
  • You can specify a custom column with the :column_name option
  • You can specify a custom method via a symbol or a proc

Example:

class User
  acts_as_google_authenticated :column_name => :user_name
end

@user = User.new(:user_name => "ted")
@user.google_label                      # => "ted"

class User
	acts_as_google_authenticated :method => :user_name_with_label

	def user_name_with_label
	  "#{user_name}@example.com"
	end
end

@user = User.new(:user_name => "ted")
@user.google_label                    # => "[email protected]"

class User
	acts_as_google_authenticated :method => Proc.new { |user| user.user_name_with_label.upcase }

	def user_name_with_label
	  "#{user_name}@example.com"
	end
end

@user = User.new(:user_name => "ted")
@user.google_label                    # => "[email protected]"

Here's what the labels look like in Google Authenticator for iPhone:

iPhone Label Screenshot

Google Secret

The "google secret" is where GoogleAuthenticatorRails stores the secret token used to generate the MFA code.

You can also specify a column for storing the google secret. The default is google_secret.

Example

class User
	acts_as_google_authenticated :google_secret_column => :mfa_secret
end

@user = User.new
@user.set_google_secret
@user.mfa_secret 		 # => "56ahi483"

Drift

You can specify a custom drift value. Drift is the number of seconds that the client and server are allowed to drift apart. Default value is 5 seconds.

class User
  act_as_google_authenticated :drift => 31
end

Lookup Token

You can also specify which column the appropriate MfaSession subclass should use to look up the record:

Example

class User
  acts_as_google_authenticated :lookup_token => :salt
end

The above will cause the UserMfaSession class to call User.where(:salt => cookie_salt) or User.scoped(:conditions => { :salt => cookie_salt }) to find the appropriate record.

A note about record lookup

GoogleAuthenticatorRails makes one very large assumption when attempting to lookup a record. If your MfaSession subclass is named UserMfaSession it assumes you're trying to lookup a User record. Currently, there is no way to configure this, so if you're trying to lookup a VeryLongModelNameForUser you'll need to name your MfaSession subclass VeryLongModelNameForUserMfaSession.

For example:

# app/models/user.rb
class User < ActiveRecord::Base
  acts_as_google_authenticated
end

# app/models/user_mfa_session.rb
class UserMfaSession < GoogleAuthenticatorRails::Session::Base
end

A note about cookie creation and Session::Persistence::TokenNotFound

GoogleAuthenticatorRails looks up the record based on the cookie created when you call MfaSession#create. The #create method looks into the record class (in our example, User) and looks at the configured :lookup_token option. It uses that option to save two pieces of information into the cookie, the id of the record and the token, which defaults to persistence_token. persistence_token is what Authlogic uses, which this gem was originally designed to work with.

This can cause a lot of headaches if the model isn't configured correctly, and will cause a GoogleAuthenticatorRails::Session::Persistence::TokenNotFound error.

This error appears for one of three reasons:

  1. user is nil
  2. user doesn't respond to :persistence_token
  3. user.persistence_token is blank

For example:

# app/models/user.rb
class User < ActiveRecord::Base
  acts_as_google_authenticated
end

# Model has attributes:
# id:   integer
# name: string
# salt: string

# app/models/user_mfa_session.rb
class UserMfaSession < GoogleAuthenticatorRails::Session::Base
end

# app/controllers/mfa_session_controller.rb
class MfaSessionController < ApplicationController
  def create
    UserMfaSession.create(user) # => Error: GoogleAuthenticatorRails::Session::Persistence::TokenNotFound
  end
end

The above example will fail because the User class doesn't have a persistence_token method. The fix for this is to configure actions_as_google_authentic to use the right column:

# app/models/user.rb
class User < ActiveRecord::Base
  acts_as_google_authenticated :lookup_token => :salt
end

# Model has attributes:
# id:   integer
# name: string
# salt: string

# app/models/user_mfa_session.rb
class UserMfaSession < GoogleAuthenticatorRails::Session::Base
end

# app/controllers/mfa_session_controller.rb
class MfaSessionController < ApplicationController
  def create
    UserMfaSession.create(user)
  end
end

This call to #create will succeed (as long as user.salt is not nil).

Issuer

You can also specify a name for the 'issuer' (the name of the website) where the user is using this token:

Example

class User
  acts_as_google_authenticated :issuer => 'example.com'
end

You can also use a Proc to set a dynamic issuer for multi-tenant applications or any other custom needs:

class User
  acts_as_google_authenticated :issuer => Proc.new { |user| user.admin? ? "Example Admin" : "example.com" }
end

This way your user will have the name of your site at the authenticator card besides the current token.

Here's what the issuers look like in Google Authenticator for iPhone:

iPhone Label Screenshot

Sample Rails Setup

This is a very rough outline of how GoogleAuthenticatorRails is meant to manage the sessions and cookies for a Rails app.

# Gemfile

gem 'rails'
gem 'google-authenticator-rails'

First add a field to your user model to hold the Google token.

class AddGoogleSecretToUser < ActiveRecord::Migration
  def change
    add_column :users, :google_secret, :string
  end
end
# app/models/users.rb

class User < ActiveRecord::Base
  acts_as_google_authenticated
end

If you want to authenticate based on a model called User, then you should name your session object UserMfaSession.

# app/models/user_mfa_session.rb

class UserMfaSession <  GoogleAuthenticatorRails::Session::Base
  # no real code needed here
end
# app/controllers/user_mfa_session_controller.rb

class UserMfaSessionController < ApplicationController

  def new
    # load your view
  end

  def create
    user = current_user # grab your currently logged in user
    if user.google_authentic?(params[:mfa_code])
      UserMfaSession.create(user)
      redirect_to root_path
    else
      flash[:error] = "Wrong code"
      render :new
    end
  end

end
# app/controllers/application_controller.rb

class ApplicationController < ActionController::Base
  before_filter :check_mfa

  private
  def check_mfa
     if !(user_mfa_session = UserMfaSession.find) && (user_mfa_session ? user_mfa_session.record == current_user : !user_mfa_session)
      redirect_to new_user_mfa_session_path
    end
  end
end

Cookie options

You can configure the MfaSession cookie by creating an initializer:

# config/initializers/google_authenticator_rails.rb

# The cookie normally expires in 24 hours, you can change this to 1 month
GoogleAuthenticatorRails.time_until_expiration = 1.month

# You can override the suffix of the cookie's key, by default this is mfa_credentials
GoogleAuthenticatorRails.cookie_key_suffix = 'mfa_credentials'

# Rails offers a few more cookie options, by default only :httponly is turned on, you can change it to HTTPS only:
GoogleAuthenticatorRails.cookie_options = { :httponly => true, :secure => true, :domain => :all }

Additional cookie option symbols can be found in the Ruby on Rails guide.

Destroying the Cookie

If you want to manually destroy the MFA cookie (for example, when a user logs out), just call

UserMfaSession::destroy

Storing Secrets in Encrypted Form (Rails 4.1 and above)

Normally, if an attacker gets access to the application database, they will be able to generate correct authentication codes, elmininating the security gains from two-factor authentication. If the application's secret_key_base is handled more securely than the database (by, for example, never putting it on the server filesystem), protection against database compromise can be gained by setting the :encrypt_secrets option to true. Newly-created secrets will then be stored in encrypted form.

Existing non-encrypted secrets for all models for which the :encrypt_secrets option has been set to true can be encrypted by running

  rails google_authenticator:encrypt_secrets

This may be reversed by running

  rails google_authenticator:decrypt_secrets

then by removing, or setting false, the :encrypt_secrets option.

If secret_key_base needs to change, set old_secret_key_base to the old key in config/secrets.yml before generating the new key. Then run

  rails google_authenticator:reencrypt_secrets

to change all encrypted google secret fields to use the new key.

If the app is not running under Rails version 4.1 or above, encryption will be disabled, and a warning issued if :encrypt_secrets is enabled on a model.

If encryption is enabled for a model, the Google secret column of its table must be able to hold at least 162 characters, rather than just 32.

Contributing

  1. Fork it
  2. Create your feature branch (git checkout -b my-new-feature)
  3. Commit your changes (git commit -am 'Added some feature')
  4. Push to the branch (git push origin my-new-feature)
  5. Create new Pull Request

License

MIT.

google-authenticator's People

Contributors

0lafe avatar 4geru avatar alfie-max avatar cianmce avatar daniel-casey avatar dependabot[bot] avatar dolarsrg avatar finnlawrence avatar harisadam avatar hecbuma avatar itspriddle avatar jaredonline avatar kg8m avatar louman avatar mhickman avatar mrj avatar patricktulskie avatar pbrumm avatar psujohn avatar rubemz avatar tietew avatar tsmango avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

google-authenticator's Issues

Expires after few seconds

I have set the expiry for 24 hours and it works fine.

But sometimes it expires right after few seconds for some users.

Secure MFA cookie

Perhaps it would be a good idea to disable javascript access to the MFA cookie (httponly: true) and to secure it when the site is running over SSL (secure: true).

It should be as easy as adding two lines to persistence.rb.

Before:

def create_cookie(token, user_id)
  value = [token, user_id].join('::')
  {
    :value    => value,
    :expires  => GoogleAuthenticatorRails.time_until_expiration.from_now
  }
end

After:

def create_cookie(token, user_id)
  value = [token, user_id].join('::')
  {
    :value    => value,
    :expires  => GoogleAuthenticatorRails.time_until_expiration.from_now,
    :secure   => Rails.application.config.force_ssl
    :httponly => true,
  }
end

I'm not sure if Rails.application.config.force_ssl is the best default, it would probably be better to make it configurable (just like time_until_expiration).

Wrong Code

Hi

I have this message "Wrong Code" only on production, in my local machine is everything ok. I test this in others local machine and is it correct too.
The code on Iphone App and the generated code with "ROTP::TOTP.new("755gdkcnliwxz4v2").now.to_s" are different, even when the google_secret is the same.

Can you help me?
ps: sorry my bad english

Adding the gem to the project changes the Content-Type of http response to my GraphQL API

Hello,
First of all, thank you for this very usefull and time saving gem.
Thanks to it, I could integrate MFA with Authenticar apps.

However, when deploying the feature to the testing environement, it appeared to break the JSON API of the project.
I could more or less isolate the problem that I can describe like this:

  • Beside the usual web application, my Ruby on rails project runs an http API that inherits from ActionController::API.

  • Simply adding the gem to the Gemfile changes the behaviour of this API: the Content-Type header of the response is set to 'text/plain' instead of 'application/json' and the returned data is empty. This causes api clients to break.

  • If I comment the following lines of the gem, the Content-Type header is back to 'application/json', the data is OK and the API is fixed.
    lib/google-authenticator-rails/action_controller/rails_adapter.rb, lines 44 ->46

if defined?(ActionController::API)
ActionController::API.send(:include, GoogleAuthenticatorRails::ActionController::Integration)
end

I am pretty novice to Ruby on Rails and I have to admit that I don't understand much of what's going under all this.

Do you have an idea of how I could fix or workaround the problem ?

Code difference between app and gem

Hi,

2 days ago I've added this gem to my pre-production release and registered the application by scanning the QR-Code.

I've entered the code and was logged in.

Today there is the issue, that the code does not match.
ROTP::TOTP.new(user.google_secret).now.to_s returns another code as the app displays.
The local time matches the server time, only 1 second difference.

With the above mentioned command, the code changes also one second after the app.

Gem Configuration

has_secure_token
acts_as_google_authenticated issuer: 'myappname', lookup_token: :token

The Token is a unique key, and will be generated, after the creation of a user.

What can cause this problem? :(

Rails 4

Any plans on supporting Rails 4?

google_qr_to_base64 method isn't working

Hey Jared 👋🏻

Just want to inform you that method google_qr_to_base64 is not working at all and throwing the following exception

NoMethodError (undefined method `google_qr_to_base64' for #<User:0x00007fd03baeaea8>)
Did you mean?  google_qr_uri

New Release?

Hi, can a new version be released to capture those Rails 5 deprecation fixes?

Many thanks!

No ability to destroy the mfa session

Unless I missed it there's no way to destroy the mfa session (cookie) on demand. I'd like to be able to destroy it when the user hits logout (as opposed to timing out) which is what github does.

If there really is no way to do this I'd be happy to see if I can add it.

NoMethodError: undefined method `cookies' for nil:NilClass

when i call http://xxx/api/v1/user_mfa_session/new then throw exception

{
"status": 500,
"error": "Internal Server Error",
"exception": "#<NoMethodError: undefined method cookies' for nil:NilClass>", "traces": { "Application Trace": [ { "id": 1, "trace": "app/controllers/api/v1/user_mfa_sessions_controller.rb:26:in check_mfa'"
}
],
"Framework Trace": [
{
"id": 0,
"trace": "google-authenticator-rails (1.6.1) lib/google-authenticator-rails/session/persistence.rb:16:in find'" }, { "id": 2, "trace": "activesupport (5.1.5) lib/active_support/callbacks.rb:413:in block in make_lambda'"
},
{
"id": 3,
"trace": "activesupport (5.1.5) lib/active_support/callbacks.rb:197:in block (2 levels) in halting'" }, { "id": 4, "trace": "actionpack (5.1.5) lib/abstract_controller/callbacks.rb:12:in block (2 levels) in module:Callbacks'"
},
{
"id": 5,
"trace": "activesupport (5.1.5) lib/active_support/callbacks.rb:198:in block in halting'" }, { "id": 6, "trace": "activesupport (5.1.5) lib/active_support/callbacks.rb:507:in block in invoke_before'"
},
{
"id": 7,
"trace": "activesupport (5.1.5) lib/active_support/callbacks.rb:507:in each'" }, { "id": 8, "trace": "activesupport (5.1.5) lib/active_support/callbacks.rb:507:in invoke_before'"
},
{
"id": 9,
"trace": "activesupport (5.1.5) lib/active_support/callbacks.rb:130:in run_callbacks'" }, { "id": 10, "trace": "actionpack (5.1.5) lib/abstract_controller/callbacks.rb:19:in process_action'"
},
{
"id": 11,
"trace": "actionpack (5.1.5) lib/action_controller/metal/rescue.rb:20:in process_action'" }, { "id": 12, "trace": "actionpack (5.1.5) lib/action_controller/metal/instrumentation.rb:32:in block in process_action'"
},
{
"id": 13,
"trace": "activesupport (5.1.5) lib/active_support/notifications.rb:166:in block in instrument'" }, { "id": 14, "trace": "activesupport (5.1.5) lib/active_support/notifications/instrumenter.rb:21:in instrument'"
},
{
"id": 15,
"trace": "activesupport (5.1.5) lib/active_support/notifications.rb:166:in instrument'" }, { "id": 16, "trace": "actionpack (5.1.5) lib/action_controller/metal/instrumentation.rb:30:in process_action'"
},
{
"id": 17,
"trace": "actionpack (5.1.5) lib/action_controller/metal/params_wrapper.rb:252:in process_action'" }, { "id": 18, "trace": "activerecord (5.1.5) lib/active_record/railties/controller_runtime.rb:22:in process_action'"
},
{
"id": 19,
"trace": "actionpack (5.1.5) lib/abstract_controller/base.rb:124:in process'" }, { "id": 20, "trace": "actionpack (5.1.5) lib/action_controller/metal.rb:189:in dispatch'"
},
{
"id": 21,
"trace": "actionpack (5.1.5) lib/action_controller/metal.rb:253:in dispatch'" }, { "id": 22, "trace": "actionpack (5.1.5) lib/action_dispatch/routing/route_set.rb:49:in dispatch'"
},
{
"id": 23,
"trace": "actionpack (5.1.5) lib/action_dispatch/routing/route_set.rb:31:in serve'" }, { "id": 24, "trace": "actionpack (5.1.5) lib/action_dispatch/journey/router.rb:50:in block in serve'"
},
{
"id": 25,
"trace": "actionpack (5.1.5) lib/action_dispatch/journey/router.rb:33:in each'" }, { "id": 26, "trace": "actionpack (5.1.5) lib/action_dispatch/journey/router.rb:33:in serve'"
},
{
"id": 27,
"trace": "actionpack (5.1.5) lib/action_dispatch/routing/route_set.rb:844:in call'" }, { "id": 28, "trace": "apipie-rails (0.5.6) lib/apipie/static_dispatcher.rb:65:in call'"
},
{
"id": 29,
"trace": "apipie-rails (0.5.6) lib/apipie/extractor/recorder.rb:136:in call'" }, { "id": 30, "trace": "rack (2.0.4) lib/rack/session/abstract/id.rb:232:in context'"
},
{
"id": 31,
"trace": "rack (2.0.4) lib/rack/session/abstract/id.rb:226:in call'" }, { "id": 32, "trace": "actionpack (5.1.5) lib/action_dispatch/middleware/cookies.rb:613:in call'"
},
{
"id": 33,
"trace": "warden (1.2.7) lib/warden/manager.rb:36:in block in call'" }, { "id": 34, "trace": "warden (1.2.7) lib/warden/manager.rb:35:in catch'"
},
{
"id": 35,
"trace": "warden (1.2.7) lib/warden/manager.rb:35:in call'" }, { "id": 36, "trace": "rack (2.0.4) lib/rack/etag.rb:25:in call'"
},
{
"id": 37,
"trace": "rack (2.0.4) lib/rack/conditional_get.rb:25:in call'" }, { "id": 38, "trace": "rack (2.0.4) lib/rack/head.rb:12:in call'"
},
{
"id": 39,
"trace": "activerecord (5.1.5) lib/active_record/migration.rb:556:in call'" }, { "id": 40, "trace": "actionpack (5.1.5) lib/action_dispatch/middleware/callbacks.rb:26:in block in call'"
},
{
"id": 41,
"trace": "activesupport (5.1.5) lib/active_support/callbacks.rb:97:in run_callbacks'" }, { "id": 42, "trace": "actionpack (5.1.5) lib/action_dispatch/middleware/callbacks.rb:24:in call'"
},
{
"id": 43,
"trace": "actionpack (5.1.5) lib/action_dispatch/middleware/executor.rb:12:in call'" }, { "id": 44, "trace": "actionpack (5.1.5) lib/action_dispatch/middleware/debug_exceptions.rb:59:in call'"
},
{
"id": 45,
"trace": "actionpack (5.1.5) lib/action_dispatch/middleware/show_exceptions.rb:31:in call'" }, { "id": 46, "trace": "railties (5.1.5) lib/rails/rack/logger.rb:36:in call_app'"
},
{
"id": 47,
"trace": "railties (5.1.5) lib/rails/rack/logger.rb:24:in block in call'" }, { "id": 48, "trace": "activesupport (5.1.5) lib/active_support/tagged_logging.rb:69:in block in tagged'"
},
{
"id": 49,
"trace": "activesupport (5.1.5) lib/active_support/tagged_logging.rb:26:in tagged'" }, { "id": 50, "trace": "activesupport (5.1.5) lib/active_support/tagged_logging.rb:69:in tagged'"
},
{
"id": 51,
"trace": "railties (5.1.5) lib/rails/rack/logger.rb:24:in call'" }, { "id": 52, "trace": "actionpack (5.1.5) lib/action_dispatch/middleware/remote_ip.rb:79:in call'"
},
{
"id": 53,
"trace": "actionpack (5.1.5) lib/action_dispatch/middleware/request_id.rb:25:in call'" }, { "id": 54, "trace": "rack (2.0.4) lib/rack/runtime.rb:22:in call'"
},
{
"id": 55,
"trace": "activesupport (5.1.5) lib/active_support/cache/strategy/local_cache_middleware.rb:27:in call'" }, { "id": 56, "trace": "actionpack (5.1.5) lib/action_dispatch/middleware/executor.rb:12:in call'"
},
{
"id": 57,
"trace": "actionpack (5.1.5) lib/action_dispatch/middleware/static.rb:125:in call'" }, { "id": 58, "trace": "rack (2.0.4) lib/rack/sendfile.rb:111:in call'"
},
{
"id": 59,
"trace": "rack-cors (1.0.2) lib/rack/cors.rb:97:in call'" }, { "id": 60, "trace": "railties (5.1.5) lib/rails/engine.rb:522:in call'"
},
{
"id": 61,
"trace": "puma (3.11.3) lib/puma/configuration.rb:225:in call'" }, { "id": 62, "trace": "puma (3.11.3) lib/puma/server.rb:624:in handle_request'"
},
{
"id": 63,
"trace": "puma (3.11.3) lib/puma/server.rb:438:in process_client'" }, { "id": 64, "trace": "puma (3.11.3) lib/puma/server.rb:302:in block in run'"
},
{
"id": 65,
"trace": "puma (3.11.3) lib/puma/thread_pool.rb:120:in block in spawn_thread'" } ], "Full Trace": [ { "id": 0, "trace": "google-authenticator-rails (1.6.1) lib/google-authenticator-rails/session/persistence.rb:16:in find'"
},
{
"id": 1,
"trace": "app/controllers/api/v1/user_mfa_sessions_controller.rb:26:in check_mfa'" }, { "id": 2, "trace": "activesupport (5.1.5) lib/active_support/callbacks.rb:413:in block in make_lambda'"
},
{
"id": 3,
"trace": "activesupport (5.1.5) lib/active_support/callbacks.rb:197:in block (2 levels) in halting'" }, { "id": 4, "trace": "actionpack (5.1.5) lib/abstract_controller/callbacks.rb:12:in block (2 levels) in module:Callbacks'"
},
{
"id": 5,
"trace": "activesupport (5.1.5) lib/active_support/callbacks.rb:198:in block in halting'" }, { "id": 6, "trace": "activesupport (5.1.5) lib/active_support/callbacks.rb:507:in block in invoke_before'"
},
{
"id": 7,
"trace": "activesupport (5.1.5) lib/active_support/callbacks.rb:507:in each'" }, { "id": 8, "trace": "activesupport (5.1.5) lib/active_support/callbacks.rb:507:in invoke_before'"
},
{
"id": 9,
"trace": "activesupport (5.1.5) lib/active_support/callbacks.rb:130:in run_callbacks'" }, { "id": 10, "trace": "actionpack (5.1.5) lib/abstract_controller/callbacks.rb:19:in process_action'"
},
{
"id": 11,
"trace": "actionpack (5.1.5) lib/action_controller/metal/rescue.rb:20:in process_action'" }, { "id": 12, "trace": "actionpack (5.1.5) lib/action_controller/metal/instrumentation.rb:32:in block in process_action'"
},
{
"id": 13,
"trace": "activesupport (5.1.5) lib/active_support/notifications.rb:166:in block in instrument'" }, { "id": 14, "trace": "activesupport (5.1.5) lib/active_support/notifications/instrumenter.rb:21:in instrument'"
},
{
"id": 15,
"trace": "activesupport (5.1.5) lib/active_support/notifications.rb:166:in instrument'" }, { "id": 16, "trace": "actionpack (5.1.5) lib/action_controller/metal/instrumentation.rb:30:in process_action'"
},
{
"id": 17,
"trace": "actionpack (5.1.5) lib/action_controller/metal/params_wrapper.rb:252:in process_action'" }, { "id": 18, "trace": "activerecord (5.1.5) lib/active_record/railties/controller_runtime.rb:22:in process_action'"
},
{
"id": 19,
"trace": "actionpack (5.1.5) lib/abstract_controller/base.rb:124:in process'" }, { "id": 20, "trace": "actionpack (5.1.5) lib/action_controller/metal.rb:189:in dispatch'"
},
{
"id": 21,
"trace": "actionpack (5.1.5) lib/action_controller/metal.rb:253:in dispatch'" }, { "id": 22, "trace": "actionpack (5.1.5) lib/action_dispatch/routing/route_set.rb:49:in dispatch'"
},
{
"id": 23,
"trace": "actionpack (5.1.5) lib/action_dispatch/routing/route_set.rb:31:in serve'" }, { "id": 24, "trace": "actionpack (5.1.5) lib/action_dispatch/journey/router.rb:50:in block in serve'"
},
{
"id": 25,
"trace": "actionpack (5.1.5) lib/action_dispatch/journey/router.rb:33:in each'" }, { "id": 26, "trace": "actionpack (5.1.5) lib/action_dispatch/journey/router.rb:33:in serve'"
},
{
"id": 27,
"trace": "actionpack (5.1.5) lib/action_dispatch/routing/route_set.rb:844:in call'" }, { "id": 28, "trace": "apipie-rails (0.5.6) lib/apipie/static_dispatcher.rb:65:in call'"
},
{
"id": 29,
"trace": "apipie-rails (0.5.6) lib/apipie/extractor/recorder.rb:136:in call'" }, { "id": 30, "trace": "rack (2.0.4) lib/rack/session/abstract/id.rb:232:in context'"
},
{
"id": 31,
"trace": "rack (2.0.4) lib/rack/session/abstract/id.rb:226:in call'" }, { "id": 32, "trace": "actionpack (5.1.5) lib/action_dispatch/middleware/cookies.rb:613:in call'"
},
{
"id": 33,
"trace": "warden (1.2.7) lib/warden/manager.rb:36:in block in call'" }, { "id": 34, "trace": "warden (1.2.7) lib/warden/manager.rb:35:in catch'"
},
{
"id": 35,
"trace": "warden (1.2.7) lib/warden/manager.rb:35:in call'" }, { "id": 36, "trace": "rack (2.0.4) lib/rack/etag.rb:25:in call'"
},
{
"id": 37,
"trace": "rack (2.0.4) lib/rack/conditional_get.rb:25:in call'" }, { "id": 38, "trace": "rack (2.0.4) lib/rack/head.rb:12:in call'"
},
{
"id": 39,
"trace": "activerecord (5.1.5) lib/active_record/migration.rb:556:in call'" }, { "id": 40, "trace": "actionpack (5.1.5) lib/action_dispatch/middleware/callbacks.rb:26:in block in call'"
},
{
"id": 41,
"trace": "activesupport (5.1.5) lib/active_support/callbacks.rb:97:in run_callbacks'" }, { "id": 42, "trace": "actionpack (5.1.5) lib/action_dispatch/middleware/callbacks.rb:24:in call'"
},
{
"id": 43,
"trace": "actionpack (5.1.5) lib/action_dispatch/middleware/executor.rb:12:in call'" }, { "id": 44, "trace": "actionpack (5.1.5) lib/action_dispatch/middleware/debug_exceptions.rb:59:in call'"
},
{
"id": 45,
"trace": "actionpack (5.1.5) lib/action_dispatch/middleware/show_exceptions.rb:31:in call'" }, { "id": 46, "trace": "railties (5.1.5) lib/rails/rack/logger.rb:36:in call_app'"
},
{
"id": 47,
"trace": "railties (5.1.5) lib/rails/rack/logger.rb:24:in block in call'" }, { "id": 48, "trace": "activesupport (5.1.5) lib/active_support/tagged_logging.rb:69:in block in tagged'"
},
{
"id": 49,
"trace": "activesupport (5.1.5) lib/active_support/tagged_logging.rb:26:in tagged'" }, { "id": 50, "trace": "activesupport (5.1.5) lib/active_support/tagged_logging.rb:69:in tagged'"
},
{
"id": 51,
"trace": "railties (5.1.5) lib/rails/rack/logger.rb:24:in call'" }, { "id": 52, "trace": "actionpack (5.1.5) lib/action_dispatch/middleware/remote_ip.rb:79:in call'"
},
{
"id": 53,
"trace": "actionpack (5.1.5) lib/action_dispatch/middleware/request_id.rb:25:in call'" }, { "id": 54, "trace": "rack (2.0.4) lib/rack/runtime.rb:22:in call'"
},
{
"id": 55,
"trace": "activesupport (5.1.5) lib/active_support/cache/strategy/local_cache_middleware.rb:27:in call'" }, { "id": 56, "trace": "actionpack (5.1.5) lib/action_dispatch/middleware/executor.rb:12:in call'"
},
{
"id": 57,
"trace": "actionpack (5.1.5) lib/action_dispatch/middleware/static.rb:125:in call'" }, { "id": 58, "trace": "rack (2.0.4) lib/rack/sendfile.rb:111:in call'"
},
{
"id": 59,
"trace": "rack-cors (1.0.2) lib/rack/cors.rb:97:in call'" }, { "id": 60, "trace": "railties (5.1.5) lib/rails/engine.rb:522:in call'"
},
{
"id": 61,
"trace": "puma (3.11.3) lib/puma/configuration.rb:225:in call'" }, { "id": 62, "trace": "puma (3.11.3) lib/puma/server.rb:624:in handle_request'"
},
{
"id": 63,
"trace": "puma (3.11.3) lib/puma/server.rb:438:in process_client'" }, { "id": 64, "trace": "puma (3.11.3) lib/puma/server.rb:302:in block in run'"
},
{
"id": 65,
"trace": "puma (3.11.3) lib/puma/thread_pool.rb:120:in `block in spawn_thread'"
}
]
}
}

Unable to load tasks/google_authenticator.rake

Since version 1.5.0 and also 1.6.0 it is not possible to load the file during assets precompile:

$ bin/rails assets:precompile RAILS_ENV=production
rails aborted!
LoadError: cannot load such file -- tasks/google_authenticator.rake
/vendor/bundle/ruby/2.3.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:277:in `load'
/vendor/bundle/ruby/2.3.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:277:in `block in load'
/vendor/bundle/ruby/2.3.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:249:in `load_dependency'
/vendor/bundle/ruby/2.3.0/gems/activesupport-5.2.0/lib/active_support/dependencies.rb:277:in `load'
/vendor/bundle/ruby/2.3.0/gems/google-authenticator-rails-1.5.0/lib/google-authenticator-rails.rb:32:in `block in <class:Railtie>'
/vendor/bundle/ruby/2.3.0/gems/railties-5.2.0/lib/rails/railtie.rb:246:in `instance_exec'
/vendor/bundle/ruby/2.3.0/gems/railties-5.2.0/lib/rails/railtie.rb:246:in `block in run_tasks_blocks'
/vendor/bundle/ruby/2.3.0/gems/railties-5.2.0/lib/rails/railtie.rb:255:in `each'
/vendor/bundle/ruby/2.3.0/gems/railties-5.2.0/lib/rails/railtie.rb:255:in `each_registered_block'
/vendor/bundle/ruby/2.3.0/gems/railties-5.2.0/lib/rails/railtie.rb:246:in `run_tasks_blocks'
/vendor/bundle/ruby/2.3.0/gems/railties-5.2.0/lib/rails/application.rb:514:in `block in run_tasks_blocks'
/vendor/bundle/ruby/2.3.0/gems/railties-5.2.0/lib/rails/engine/railties.rb:15:in `each'
/vendor/bundle/ruby/2.3.0/gems/railties-5.2.0/lib/rails/engine/railties.rb:15:in `each'
/vendor/bundle/ruby/2.3.0/gems/railties-5.2.0/lib/rails/application.rb:514:in `run_tasks_blocks'
/vendor/bundle/ruby/2.3.0/gems/railties-5.2.0/lib/rails/engine.rb:459:in `load_tasks'
/Rakefile:6:in `<top (required)>'
/vendor/bundle/ruby/2.3.0/gems/railties-5.2.0/lib/rails/commands/rake/rake_command.rb:22:in `block in perform'
/vendor/bundle/ruby/2.3.0/gems/railties-5.2.0/lib/rails/commands/rake/rake_command.rb:20:in `perform'
/vendor/bundle/ruby/2.3.0/gems/railties-5.2.0/lib/rails/command.rb:48:in `invoke'
/vendor/bundle/ruby/2.3.0/gems/railties-5.2.0/lib/rails/commands.rb:18:in `<top (required)>'
bin/rails:4:in `require'
bin/rails:4:in `<main>'
(See full trace by running task with --trace)

I use it with Rails 5.2.0.

The 1.4.1 version works ok. What changes are done of what can I do to give better feedback?

undefined method `prepend_before_filter' for ActionController::Base:Class

After bundling the gem, I get the error message above and neither can start my application nor generaate the migrations. I use rails 5 and ruby 2.6.

I could not find anything about this error message online and also was not able to find out how to deal with this issue.

Any ideas what I could do?

Newer Version of ROTP

With Ruby 3.0 I get the following error when calling up user.google_qr_uri: .bundle/ruby/3.0.0/gems/rotp-3.3.0/lib/rotp/totp.rb:84:in provisioning_uri': undefined method encode' for URI:Module (NoMethodError).

This seems to be resolved with an updated dependency. Unfortunately I do not know how to do that, which is why I did not open a pull request.

`RailsAdapter::LoadedTooLateError` occurs if Zeitwerk is enabled

Hi. Thank you for developing this gem.

I have an issue where GoogleAuthenticatorRails::ActionController::RailsAdapter::LoadedTooLateError occurs when running RSpec tests on Rails with Zeitwerk. This issue is the same as mentioned in #63 (comment).

This issue is caused by defined?(::ApplicationController) always returning "constant" when Zeitwerk is enabled. Zeitwerk uses Ruby's built-in autoload, so this issue is originally caused by autoload.

I'll create a pull request to fix this issue soon. I hope you can check it out.


Note: You can reproduce the autoload and defined? behavior as follows:

  1. Put sample.rb:
    class Sample
    end
  2. Run ruby -e 'p defined?(Sample)' in your shell:
    • You will see nil because Sample isn't loaded
  3. Run ruby -e 'autoload :Sample, "./sample"; p defined?(Sample)' in your shell:
    • You will see "constant" even though Sample isn't loaded because Sample is an autoload constant

More direction in readme in regards to the token

Hey Jared

So I'm having a hard time understanding what needs to be done in regards to the google_lookup_token. Not sure if I should be adding this field to my table and setting it my self etc...

I was able to get the secret created and show the QR with no problems.
After attempting to create the session however I get hit with: GoogleAuthenticatorRails::Session::Persistence::TokenNotFound

So I guess what I'm trying to figure out is what actually needs to be configured in regards to the token if anything? Seems like I or the documentation missed a step?

Thanks Jared

Use with specific roles?

Is it possible to use this gem for a specific 'role' if I have a single User table with multiple roles?

[Error] prepend a before_filter in ActionController::Base

Am getting the following error.

GoogleAuthenticatorRails is trying to prepend a before_filter in ActionController::Base. Because you've already defined ApplicationController, your controllers will not get this before_filter. Please load GoogleAuthenticatorRails before defining ApplicationController.

I have ApiController & ApplicationController both defined as follows:
class ApiController < ActionController::API
class ApplicationController < ActionController::Base

Am on:
ruby '2.7.7'
rails '6.1.7.3'

Please help me solve this!
Thanks in advance!

Problème avec GoogleAuthenticatorRails::Session::Persistence::TokenNotFound

Bonjour,

C'est la première fois que j'écris un poste donc soyer indulgent ^^.
Mon problème, comme le titre le dit, j'ai un problème lors de mon check pour email et le mfa_code, tout est bon mais la page d'après, j'ai GoogleAuthenticatorRails::Session::Persistence::TokenNotFound in UserMfaSessionsController#create.

Mon code est quasiment le même que le tient. Si vous avez des pistes, je suis preneur... :'(
merci de vos aides , Mader

QR codes without Google Charts

Google charts is a shortcut for creating QR codes, but it would be better to build them inside this app to avoid sending secret keys to Google.

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.