Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LG-10687 Break Up MFA Presenters #9211

Merged
merged 15 commits into from
Sep 28, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/models/auth_app_configuration.rb
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ def mfa_enabled?

def selection_presenters
if mfa_enabled?
[TwoFactorAuthentication::AuthAppSelectionPresenter.new(user:, configuration: self)]
[TwoFactorAuthentication::SignInAuthAppSelectionPresenter.new(user:, configuration: self)]
else
[]
end
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,6 @@ def disabled?

def login_label(type)
case type
when 'auth_app'
t('two_factor_authentication.login_options.auth_app')
when 'backup_code'
t('two_factor_authentication.login_options.backup_code')
when 'personal_key'
Expand All @@ -92,8 +90,6 @@ def login_label(type)

def setup_label(type)
case type
when 'auth_app'
t('two_factor_authentication.two_factor_choice_options.auth_app')
when 'backup_code'
t('two_factor_authentication.two_factor_choice_options.backup_code')
when 'piv_cac'
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
module TwoFactorAuthentication
class SetUpAuthAppSelectionPresenter < SetUpSelectionPresenter
def method
:auth_app
end

def mfa_configuration_count
user.auth_app_configurations.count
end

def label
t('two_factor_authentication.two_factor_choice_options.auth_app')
end

def info
t('two_factor_authentication.two_factor_choice_options.auth_app_info')
mdiarra3 marked this conversation as resolved.
Show resolved Hide resolved
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
module TwoFactorAuthentication
class SetUpSelectionPresenter
include ActionView::Helpers::TranslationHelper

attr_reader :user

def initialize(user:)
@user = user
end

def render_in(view_context, &block)
view_context.capture(&block)
end

def type
method.to_s
end

def label
raise "Unsupported setup method: #{type}"
end

def info
raise "Unsupported setup method: #{type}"
end

def mfa_added_label
if single_configuration_only?
''
else
"(#{mfa_configuration_description})"
end
end

def single_configuration_only?
false
end

def mfa_configuration_count
0
end

def mfa_configuration_description
return '' if mfa_configuration_count == 0
if single_configuration_only?
t('two_factor_authentication.two_factor_choice_options.no_count_configuration_added')
else
t(
'two_factor_authentication.two_factor_choice_options.configurations_added',
count: mfa_configuration_count,
)
end
end

def disabled?
single_configuration_only? && mfa_configuration_count > 0
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
module TwoFactorAuthentication
class SignInAuthAppSelectionPresenter < SignInSelectionPresenter
def method
:auth_app
end

def label
t('two_factor_authentication.login_options.auth_app')
end

def info
t('two_factor_authentication.login_options.auth_app_info')
end
end
end
mdiarra3 marked this conversation as resolved.
Show resolved Hide resolved
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
module TwoFactorAuthentication
class SignInSelectionPresenter
include ActionView::Helpers::TranslationHelper

attr_reader :configuration, :user

def initialize(user:, configuration:)
@user = user
@configuration = configuration
end

def render_in(view_context, &block)
view_context.capture(&block)
end

def type
method.to_s
end

def label
raise "Unsupported login method: #{type}"
end

def info
raise "Unsupported login method: #{type}"
end

def disabled?
false
end
aduth marked this conversation as resolved.
Show resolved Hide resolved
end
end
2 changes: 1 addition & 1 deletion app/presenters/two_factor_options_presenter.rb
Original file line number Diff line number Diff line change
Expand Up @@ -99,7 +99,7 @@ def phone_options

def totp_option
return [] if piv_cac_required? || phishing_resistant_only?
[TwoFactorAuthentication::AuthAppSelectionPresenter.new(user: user)]
[TwoFactorAuthentication::SetUpAuthAppSelectionPresenter.new(user: user)]
end

def backup_code_option
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,14 @@
require 'rails_helper'

RSpec.describe TwoFactorAuthentication::AuthAppSelectionPresenter do
RSpec.describe TwoFactorAuthentication::SetUpAuthAppSelectionPresenter do
let(:configuration) {}
let(:user_without_mfa) { create(:user) }
let(:user_with_mfa) { create(:user, :with_authentication_app) }
let(:presenter_without_mfa) do
described_class.new(configuration: configuration, user: user_without_mfa)
described_class.new(user: user_without_mfa)
end
let(:presenter_with_mfa) do
described_class.new(configuration: configuration, user: user_with_mfa)
described_class.new(user: user_with_mfa)
end

describe '#type' do
Expand All @@ -17,7 +17,7 @@
end
end

describe '#mfa_configruation' do
describe '#mfa_configuration' do
it 'return an empty string when user has not configured this authenticator' do
expect(presenter_without_mfa.mfa_configuration_description).to eq('')
end
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
require 'rails_helper'

RSpec.describe TwoFactorAuthentication::SetUpSelectionPresenter do
class PlaceholderPresenter < TwoFactorAuthentication::SetUpSelectionPresenter
def method
:missing
end
end

let(:user) { build(:user) }

subject(:presenter) { described_class.new(user: user) }

describe '#render_in' do
it 'renders captured block content' do
view_context = ActionController::Base.new.view_context

expect(view_context).to receive(:capture) do |*args, &block|
expect(block.call).to eq('content')
end

presenter.render_in(view_context) { 'content' }
end
end

describe '#disabled?' do
let(:single_configuration_only) {}
let(:mfa_configuration_count) {}

before do
allow(presenter).to receive(:single_configuration_only?).and_return(single_configuration_only)
allow(presenter).to receive(:mfa_configuration_count).and_return(mfa_configuration_count)
end

context 'without single configuration restriction' do
let(:single_configuration_only) { false }

it 'is an mfa that allows multiple configurations' do
expect(presenter.disabled?).to eq(false)
end
end

context 'with single configuration only' do
let(:single_configuration_only) { true }

context 'with default mfa count implementation' do
before do
allow(presenter).to receive(:mfa_configuration_count).and_call_original
end

it 'is mfa with unimplemented mfa count and single config' do
expect(presenter.disabled?).to eq(false)
end
end

context 'with no configured mfas' do
let(:mfa_configuration_count) { 0 }

it 'is configured with no mfa' do
expect(presenter.disabled?).to eq(false)
end
end

context 'with at least one configured mfa' do
let(:mfa_configuration_count) { 1 }

it 'is mfa with at least one configured' do
expect(presenter.disabled?).to eq(true)
end
end
end
end

describe '#mfa_added_label' do
subject(:mfa_added_label) { presenter.mfa_added_label }
before do
allow(presenter).to receive(:mfa_configuration_count).and_return('1')
end
it 'is a count of configured MFAs' do
expect(presenter.mfa_added_label).to include('added')
end

context 'with single configuration only' do
before do
allow(presenter).to receive(:single_configuration_only?).and_return(true)
end

it 'is an empty string' do
expect(presenter.mfa_added_label).to eq('')
end
end
end

describe '#label' do
it 'raises with missing translation' do
expect { PlaceholderPresenter.new(user: user).label }.to raise_error(RuntimeError)
end
end

describe '#info' do
it 'raises with missing translation' do
expect { PlaceholderPresenter.new(user: user).info }.to raise_error(RuntimeError)
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
require 'rails_helper'

RSpec.describe TwoFactorAuthentication::SignInAuthAppSelectionPresenter do
let(:user) { create(:user) }
let(:configuration) { create(:auth_app_configuration, user: user) }

let(:presenter) do
described_class.new(user: user, configuration: configuration)
end

describe '#type' do
it 'returns auth_app' do
expect(presenter.type).to eq 'auth_app'
end
end

describe '#label' do
it 'raises with missing translation' do
expect(presenter.label).to eq(t('two_factor_authentication.login_options.auth_app'))
end
end

describe '#info' do
it 'raises with missing translation' do
expect(presenter.info).to eq(t('two_factor_authentication.login_options.auth_app_info'))
end
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
require 'rails_helper'

RSpec.describe TwoFactorAuthentication::SignInSelectionPresenter do
class PlaceholderPresenter < TwoFactorAuthentication::SignInSelectionPresenter
def method
:missing
end
end

let(:user) { build(:user) }
let(:configuration) { create(:phone_configuration, user: user) }

subject(:presenter) { PlaceholderPresenter.new(user: user, configuration: configuration) }

describe '#render_in' do
it 'renders captured block content' do
view_context = ActionController::Base.new.view_context

expect(view_context).to receive(:capture) do |*args, &block|
expect(block.call).to eq('content')
end

presenter.render_in(view_context) { 'content' }
end
end

describe '#label' do
it 'raises with missing translation' do
expect do
presenter.label
end.to raise_error(RuntimeError)
end
end

describe '#type' do
it 'returns missing as type' do
expect(presenter.type).to eq('missing')
end
end

describe '#info' do
it 'raises with missing translation' do
expect do
presenter.info
end.to raise_error(RuntimeError)
end
end
end
Loading