Last active
March 1, 2020 16:07
-
-
Save ace-subido/da07183a1c4a256e8beaa8b92e1ae94c to your computer and use it in GitHub Desktop.
AdminUsers::Operations::SetupTwoFactor code
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# 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 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
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?