authentication_method_spec.rb 4.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. require 'rotp'
  4. RSpec.describe Auth::TwoFactor::AuthenticationMethod, current_user_id: 1 do
  5. subject(:instance) { described_class.new(user) }
  6. let(:user) { create(:user) }
  7. shared_examples 'responding to provided instance method' do |method|
  8. it "responds to '.#{method}'" do
  9. expect(instance).to respond_to(method)
  10. end
  11. end
  12. shared_examples "raising 'NotImplemented' error for base methods" do |method, args = []|
  13. it "raises 'NotImplemented' error for '.#{method}'" do
  14. expect { instance.method(method).call(*args) }.to raise_error(NotImplementedError)
  15. end
  16. end
  17. shared_examples 'returning expected value' do |method, value, args = [], assertion: 'be'|
  18. it "returns expected value for '.#{method}'", if: assertion == 'eq' do
  19. expect(instance.method(method).call(*args)).to eq(value)
  20. end
  21. it "returns expected value for '.#{method}'", if: assertion == 'be' do
  22. expect(instance.method(method).call(*args)).to be(value)
  23. end
  24. end
  25. it_behaves_like 'responding to provided instance method', :verify
  26. it_behaves_like 'responding to provided instance method', :available?
  27. it_behaves_like 'responding to provided instance method', :enabled?
  28. it_behaves_like 'responding to provided instance method', :method_name
  29. it_behaves_like 'responding to provided instance method', :related_setting_name
  30. it_behaves_like 'responding to provided instance method', :initiate_configuration
  31. it_behaves_like 'responding to provided instance method', :create_user_config
  32. it_behaves_like 'responding to provided instance method', :destroy_user_config
  33. it_behaves_like "raising 'NotImplemented' error for base methods", :verify, [ nil, nil ]
  34. it_behaves_like "raising 'NotImplemented' error for base methods", :initiate_configuration
  35. it_behaves_like 'returning expected value', :available?, true
  36. it_behaves_like 'returning expected value', :enabled?, nil
  37. it_behaves_like 'returning expected value', :method_name, 'authentication_method', assertion: 'eq'
  38. it_behaves_like 'returning expected value', :related_setting_name, 'two_factor_authentication_method_authentication_method', assertion: 'eq'
  39. describe '#create_user_config' do
  40. let(:secret) { ROTP::Base32.random_base32 }
  41. let(:data) do
  42. {
  43. secret: secret,
  44. provisioning_uri: ROTP::TOTP.new(secret, issuer: 'Zammad CI').provisioning_uri(user.login),
  45. }
  46. end
  47. it 'saves two factor configuration for the user' do
  48. instance.create_user_config(data)
  49. expect(user.two_factor_preferences).to include(User::TwoFactorPreference)
  50. end
  51. context 'with existing configuration' do
  52. let!(:two_factor_pref) { create(:user_two_factor_preference, :security_keys, method: 'authentication_method', user: user) }
  53. let(:data) do
  54. {
  55. 'credentials' => [
  56. *two_factor_pref.configuration[:credentials],
  57. {
  58. 'external_id' => Faker::Alphanumeric.alpha(number: 70),
  59. 'public_key' => Faker::Alphanumeric.alpha(number: 128),
  60. 'nickname' => Faker::Lorem.unique.word,
  61. 'sign_count' => '0',
  62. 'created_at' => Time.zone.now,
  63. },
  64. ]
  65. }
  66. end
  67. it 'updates two factor configuration for the user' do
  68. instance.create_user_config(data)
  69. expect(two_factor_pref.reload.configuration).to eq(data)
  70. end
  71. end
  72. end
  73. describe '#update_user_config' do
  74. let!(:two_factor_pref) { create(:user_two_factor_preference, :authenticator_app, method: 'authentication_method', user: user) }
  75. let(:secret) { ROTP::Base32.random_base32 }
  76. let(:data) do
  77. {
  78. 'code' => two_factor_pref.configuration[:code],
  79. 'secret' => secret,
  80. 'provisioning_uri' => ROTP::TOTP.new(secret, issuer: 'Zammad CI').provisioning_uri(user.login),
  81. }
  82. end
  83. it 'updates two factor configuration for the user' do
  84. instance.update_user_config(data)
  85. expect(two_factor_pref.reload.configuration).to eq(data)
  86. end
  87. end
  88. describe '#destroy_user_config' do
  89. before { create(:user_two_factor_preference, :authenticator_app, method: 'authentication_method', user: user) }
  90. it 'removes two factor configuration for the user' do
  91. instance.destroy_user_config
  92. expect(user.reload.two_factor_preferences).to be_empty
  93. end
  94. context 'with existing recovery codes' do
  95. it 'deletes recovery code', :aggregate_failures do
  96. instance.destroy_user_config
  97. expect(user.reload.two_factor_preferences.authentication_methods).to be_empty
  98. expect(user.reload.two_factor_preferences.recovery_codes).to be_nil
  99. end
  100. end
  101. end
  102. end