password_spec.rb 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. # Copyright (C) 2012-2024 Zammad Foundation, https://zammad-foundation.org/
  2. require 'rails_helper'
  3. require 'system/examples/security_keys_setup_examples'
  4. require 'system/examples/authenticator_app_setup_examples'
  5. RSpec.describe 'Profile > Password', authenticated_as: :user, type: :system do
  6. let(:user) { create(:agent, :with_valid_password) }
  7. describe 'visibility' do
  8. it 'not available if both two factor and password changing disabled' do
  9. password_and_authenticate(password: false, two_factor: false)
  10. visit 'profile/'
  11. expect(page).to have_no_text('Password & Authentication')
  12. end
  13. it 'shows only password changing form if two factor disabled' do
  14. password_and_authenticate(password: true, two_factor: false)
  15. visit 'profile/password'
  16. expect(page)
  17. .to have_text('Change Your Password')
  18. .and have_no_text('Two-factor Authentication')
  19. end
  20. it 'shows only two factor if password changing disabled' do
  21. password_and_authenticate(password: false, two_factor: true)
  22. visit 'profile/password'
  23. expect(page)
  24. .to have_no_text('Change Your Password')
  25. .and have_text('Two-factor Authentication')
  26. end
  27. def password_and_authenticate(password:, two_factor:)
  28. Setting.set('two_factor_authentication_method_authenticator_app', two_factor)
  29. Setting.set('two_factor_authentication_enforce_role_ids', [])
  30. Setting.set('user_show_password_login', password)
  31. end
  32. end
  33. context 'when changing password' do
  34. before do
  35. visit 'profile/password'
  36. end
  37. it 'when current password is wrong, show error' do
  38. fill_in 'password_old', with: 'nonexisting'
  39. fill_in 'password_new', with: 'some'
  40. fill_in 'password_new_confirm', with: 'some'
  41. click '.btn--primary'
  42. expect(page).to have_text 'The current password you provided is incorrect.'
  43. end
  44. it 'when new passwords do not match, show error' do
  45. fill_in 'password_old', with: user.password_plain
  46. fill_in 'password_new', with: 'some'
  47. fill_in 'password_new_confirm', with: 'some2'
  48. click '.btn--primary'
  49. expect(page).to have_text 'passwords do not match'
  50. end
  51. it 'when new password is invalid, show error' do
  52. fill_in 'password_old', with: user.password_plain
  53. fill_in 'password_new', with: 'some'
  54. fill_in 'password_new_confirm', with: 'some'
  55. click '.btn--primary'
  56. expect(page).to have_text 'Invalid password'
  57. end
  58. it 'allows to change password' do
  59. new_password = generate(:password_valid)
  60. fill_in 'password_old', with: user.password_plain
  61. fill_in 'password_new', with: new_password
  62. fill_in 'password_new_confirm', with: new_password
  63. click '.btn--primary'
  64. expect(page).to have_text 'Password changed successfully!'
  65. end
  66. end
  67. context 'when managing two factor authentication' do
  68. before do
  69. Setting.set('two_factor_authentication_method_authenticator_app', true)
  70. Setting.set('two_factor_authentication_recovery_codes', false)
  71. Setting.set('two_factor_authentication_enforce_role_ids', [])
  72. end
  73. context 'without a configured method' do
  74. before do
  75. visit 'profile/password'
  76. end
  77. it 'shows available method' do
  78. expect(page).to have_text('Authenticator App')
  79. end
  80. it 'allows to setup two factor authentication' do
  81. within('tr[data-two-factor-key="authenticator_app"]') do
  82. expect(page).to have_css('.icon.icon-small-dot')
  83. click '.js-action'
  84. find('a', text: 'Set Up').click
  85. end
  86. setup_authenticator_app_method(user: user, password_check: user.password_plain)
  87. within('tr[data-two-factor-key="authenticator_app"]') do
  88. expect(page).to have_css('.icon.icon-checkmark')
  89. expect(page).to have_text('Default')
  90. end
  91. end
  92. it 'does not show recovery codes button' do
  93. expect(page).to have_no_text('recovery codes')
  94. end
  95. end
  96. context 'with a configured method' do
  97. let(:recovery_codes_enabled) { true }
  98. before do
  99. Setting.set('two_factor_authentication_recovery_codes', recovery_codes_enabled)
  100. create(:user_two_factor_preference, :authenticator_app, user: user)
  101. visit 'profile/password'
  102. end
  103. it 'shows configured method as ready' do
  104. within('tr[data-two-factor-key="authenticator_app"]') do
  105. expect(page).to have_css('.icon.icon-checkmark')
  106. expect(page).to have_text('Default')
  107. end
  108. end
  109. it 'allows to remove an existing two factor authentication' do
  110. within('tr[data-two-factor-key="authenticator_app"]') do
  111. click '.js-action'
  112. find('a', text: 'Remove').click
  113. end
  114. in_modal do
  115. fill_in 'Password', with: user.password_plain
  116. click_on 'Remove'
  117. end
  118. within('tr[data-two-factor-key="authenticator_app"]') do
  119. expect(page).to have_css('.icon.icon-small-dot')
  120. end
  121. end
  122. it 'allows to regenerate recovery codes' do
  123. click '.js-generate-recovery-codes'
  124. in_modal do
  125. expect(page).to have_text('Generate recovery codes: Confirm Password')
  126. fill_in 'Password', with: user.password_plain
  127. click_on 'Next'
  128. end
  129. in_modal do
  130. expect(page).to have_text('Generate recovery codes: Save Codes')
  131. stored_codes_amount = user.two_factor_preferences.recovery_codes.configuration[:codes].count
  132. displayed_codes_amount = find('.two-factor-auth code').text.tr("\n", ' ').split.count
  133. expect(stored_codes_amount).to eq(displayed_codes_amount)
  134. expect(page).to have_button("OK, I've saved my recovery codes")
  135. end
  136. end
  137. context 'when recovery codes disabled' do
  138. let(:recovery_codes_enabled) { false }
  139. it 'does not show recovery codes button if recovery codes disabled' do
  140. expect(page).to have_no_text('recovery codes')
  141. end
  142. end
  143. context 'with security keys method' do
  144. before do
  145. within('tr[data-two-factor-key="security_keys"]') do
  146. click '.js-action'
  147. find('a', text: 'Set Up').click
  148. end
  149. end
  150. include_examples 'security keys setup' do
  151. let(:current_user) { user }
  152. end
  153. end
  154. end
  155. end
  156. end