Skip to content

Instantly share code, notes, and snippets.

@ace-subido
Last active March 1, 2020 16:07
Show Gist options
  • Save ace-subido/da07183a1c4a256e8beaa8b92e1ae94c to your computer and use it in GitHub Desktop.
Save ace-subido/da07183a1c4a256e8beaa8b92e1ae94c to your computer and use it in GitHub Desktop.
AdminUsers::Operations::SetupTwoFactor code
module AdminUsers
class Authenticate
extend LightService::Action
expects :email, :password, :otp_attempt
promises :admin_user
executed do |c|
admin_user = AdminUser.find_by(email: c.email)
c.admin_user = admin_user
# this means the user doesn't exist
c.fail_and_return! "Invalid Email and Password" unless admin_user.present?
# devise built-in method
unless admin_user.valid_password?(c.password)
c.fail_and_return! "Invalid Email and Password"
end
if admin_user.otp_required_for_login
if c.otp_attempt.blank?
message = [
"You have 2-factor authentication enabled,",
"please enter your six-digit code",
].join(" ")
c.fail_and_return! message
end
unless validate_otp_attempt(admin_user, c.otp_attempt)
c.fail_and_return! "Invalid six-digit code"
end
end
end
def self.validate_otp_attempt(admin_user, code)
totp = admin_user.otp
# devise 2FA method
totp.verify_with_drift(code, admin_user.class.otp_allowed_drift)
end
private_class_method :validate_otp_attempt
end
end
# source of SetupTwoFactor as asked by many in this article: https://medium.com/@acesubido/adding-two-factor-authentication-in-activeadmin-2ed134b60042
# Using Trailblazer 2.0
# app/concepts/admin_users/operations/setup_two_factor.rb
module AdminUsers
module Operations
class SetupTwoFactor < ApplicationOperation
step Model(AdminUser, :find)
step Contract::Build(constant: Contracts::SetupTwoFactor)
step Contract::Validate(key: :admin_user)
step Contract::Persist(method: :sync)
success :set_otp_secret!
step Contract::Persist(method: :save)
def set_otp_secret!(options, params:, **)
if options['model'].otp_required_for_login
unless options['model'].otp_secret.present?
options['model'].otp_secret = AdminUser.generate_otp_secret
end
end
end
end
end
end
# app/concepts/admin_users/contacts/setup_two_factor.rb
module AdminUsers
module Contracts
class SetupTwoFactor < ApplicationContract
property :otp_required_for_login, type: Types::Form::Bool
end
end
end
@manishnagdewani96170
Copy link

Hi ace-subido, I am getting issues when trying to use this code with ruby-2.2.7.Can you help me to solve this issue?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment