jaredonline / google-authenticator

Ruby gem to implement Google's MFA authenticator
MIT License
307 stars 84 forks source link

NoMethodError: undefined method `cookies' for nil:NilClass #48

Closed marknguyen85 closed 6 years ago

marknguyen85 commented 6 years ago

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:incheck_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:inblock 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:inblock (2 levels) in '" }, { "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:inblock 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:ininvoke_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:inprocess_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:inblock 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:ininstrument'" }, { "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:inprocess_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:inprocess_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:indispatch'" }, { "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:indispatch'" }, { "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:inblock 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:inserve'" }, { "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:incall'" }, { "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:incontext'" }, { "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:incall'" }, { "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:incatch'" }, { "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:incall'" }, { "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:incall'" }, { "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:inblock 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:incall'" }, { "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:incall'" }, { "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:incall_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:inblock 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:intagged'" }, { "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:incall'" }, { "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:incall'" }, { "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:incall'" }, { "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:incall'" }, { "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:incall'" }, { "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:inhandle_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:inblock 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:infind'" }, { "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:inblock 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:inblock (2 levels) in '" }, { "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:inblock 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:ininvoke_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:inprocess_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:inblock 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:ininstrument'" }, { "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:inprocess_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:inprocess_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:indispatch'" }, { "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:indispatch'" }, { "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:inblock 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:inserve'" }, { "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:incall'" }, { "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:incontext'" }, { "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:incall'" }, { "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:incatch'" }, { "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:incall'" }, { "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:incall'" }, { "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:inblock 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:incall'" }, { "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:incall'" }, { "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:incall_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:inblock 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:intagged'" }, { "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:incall'" }, { "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:incall'" }, { "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:incall'" }, { "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:incall'" }, { "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:incall'" }, { "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:inhandle_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:inblock in run'" }, { "id": 65, "trace": "puma (3.11.3) lib/puma/thread_pool.rb:120:in `block in spawn_thread'" } ] } }

jaredonline commented 6 years ago

Heya @marknguyen85, can you give me some more details?

Which version of Rails are you using? What are the contents of your Session class? What about the associated ActiveRecord model?

marknguyen85 commented 6 years ago

@jaredonline here my code implementation

=======================================

Gemfile

gem 'rails', '~> 5.1.5'

gem 'google-authenticator-rails'

=======================================

ApplicationController.rb

class ApplicationController < ActionController::API
    include Response
    include ExceptionHandler
    include ActionController::Helpers
    include ActionController::Cookies
    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

=======================================

app/controllers/user_mfa_sessions_controller.rb

module Api
  module V1
    class UserMfaSessionsController < ApplicationController
      before_action :check_mfa
      def new
        @user = User.find_by_ermail('admin@gmail.com') 
      end
      def create
        @user = User.find_by_ermail('admin@gmail.com') 
        if @user.google_authentic?(params[:auth][:mfa_code])
          UserMfaSession.create(@user)
          redirect_to root_url
        else
          flash[:error] = "Wrong code"
          render :new
        end
      end
    end
  end
end

=======================================

model/UserMfaSession.rb

class UserMfaSession < GoogleAuthenticatorRails::Session::Base
    #no real code needed here
  end

=======================================

model/User.rb

class User < ApplicationRecord
    devise :database_authenticatable, :registerable, :recoverable, :rememberable, :trackable, :validatable
        validates :UserName, :email, :presence => true
        validates_uniqueness_of :email

    acts_as_google_authenticated lookup_token: :salt, drift: 30, issuer: 'test'
    before_save {|record| record.salt = SecureRandom.hex unless record.salt }
    after_create {|record| record.set_google_secret }
end

=======================================

config/initializers/google_authenticator_rails.rb

GoogleAuthenticatorRails.time_until_expiration = 1.month
GoogleAuthenticatorRails.cookie_key_suffix = 'mfa_credentials'
GoogleAuthenticatorRails.cookie_options = { :httponly => true, :secure => true, :domain => :all }

=======================================

config/Application.rb

module WebAPIs
  class Application < Rails::Application
    config.load_defaults 5.1
    config.api_only = true

    config.middleware.use ActionDispatch::Cookies
    config.middleware.use ActionDispatch::Session::CookieStore
  end
end
jaredonline commented 6 years ago

Ah! I think this is the problem:

class ApplicationController < ActionController::API

Right now this gem only works with ActionController::Base, its included here:

https://github.com/jaredonline/google-authenticator/blob/master/lib/google-authenticator-rails/action_controller/rails_adapter.rb#L38

There's an open PR here https://github.com/jaredonline/google-authenticator/pull/37/files to add support for ActionController::API, but I never closed it because the author never got back to me.

I'll take a look into adding that support today.

jaredonline commented 6 years ago

Alternatively, if you don't want to wait, you can have ApplicationController inherit from ActionController::Base instead of ActionController::API.

marknguyen85 commented 6 years ago

I will try according to your intructions, thanks

marknguyen85 commented 6 years ago

@jaredonline okie my issue resolved. thanks for supported.

PeterKarpinski commented 1 year ago

Hi there! I still experience this issue. My app is configured to inherit from ActionController::API and I would rather not change that. Is it possible to add support for ActionController::API? Best regards

jaredonline commented 1 year ago

@PeterKarpinski I just merged a change that should fix it. I'll roll a new version shortly.

jaredonline commented 1 year ago

@PeterKarpinski Gem 3.3.0 is available now.