diff --git a/.circleci/config.yml b/.circleci/config.yml index f9bde26afaf..4b90fbd252e 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -299,7 +299,7 @@ jobs: name: 'Smoke tests' command: | bin/smoke_test --remote --no-source-env - # - notify-slack-smoke-test-status + - notify-slack-smoke-test-status - store-smoketest-results smoketest-int: working_directory: ~/identity-idp @@ -318,7 +318,7 @@ jobs: name: 'Smoke tests' command: | bin/smoke_test --remote --no-source-env - # - notify-slack-smoke-test-status + - notify-slack-smoke-test-status - store-smoketest-results smoketest-staging: working_directory: ~/identity-idp @@ -337,7 +337,7 @@ jobs: name: 'Smoke tests' command: | bin/smoke_test --remote --no-source-env - # - notify-slack-smoke-test-status + - notify-slack-smoke-test-status - store-smoketest-results smoketest-prod: working_directory: ~/identity-idp diff --git a/Gemfile b/Gemfile index 6d0a60e6e88..39113ab29a0 100644 --- a/Gemfile +++ b/Gemfile @@ -121,7 +121,6 @@ group :test do gem 'email_spec' gem 'factory_bot_rails', '>= 5.2.0' gem 'faker' - gem 'gmail', '>= 0.7.1' gem 'rack_session_access', '>= 0.2.0' gem 'rack-test', '>= 1.1.0' gem 'rails-controller-testing', '>= 1.0.4' diff --git a/Gemfile.lock b/Gemfile.lock index dd7016aa287..ea1ec2d15d8 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -288,11 +288,6 @@ GEM ffi (~> 1.0) globalid (0.5.2) activesupport (>= 5.0) - gmail (0.7.1) - gmail_xoauth (>= 0.3.0) - mail (>= 2.2.1) - gmail_xoauth (0.4.2) - oauth (>= 0.3.6) good_job (2.2.0) activejob (>= 5.2.0) activerecord (>= 5.2.0) @@ -386,7 +381,6 @@ GEM notiffany (0.1.3) nenv (~> 0.1) shellany (~> 0.0) - oauth (0.5.6) octokit (4.19.0) faraday (>= 0.9) sawyer (~> 0.8.0, >= 0.5.3) @@ -719,7 +713,6 @@ DEPENDENCIES faker faraday foundation_emails - gmail (>= 0.7.1) good_job (~> 2.2.0) guard-rspec hashie (~> 4.1) diff --git a/spec/features/monitor/create_account_spec.rb b/spec/features/monitor/create_account_spec.rb index 86d4953312d..1a801d8cd27 100644 --- a/spec/features/monitor/create_account_spec.rb +++ b/spec/features/monitor/create_account_spec.rb @@ -11,7 +11,7 @@ context 'not staging' do before { monitor.filter_unless('STAGING') } - it 'creates new account with SMS option for 2FA' do + xit 'creates new account with SMS option for 2FA' do visit_idp_from_oidc_sp click_on 'Create an account' @@ -36,7 +36,7 @@ context 'not prod, not staging' do before { monitor.filter_unless('PROD', 'STAGING') } - it 'creates new IAL2 account with SMS option for 2FA' do + xit 'creates new IAL2 account with SMS option for 2FA' do visit_idp_from_oidc_sp_with_ial2 verify_identity_with_doc_auth expect_user_is_redirected_to_oidc_sp @@ -49,7 +49,7 @@ context 'SAML' do before { monitor.filter_if('INT') } - it 'creates new account with SMS option for 2FA' do + xit 'creates new account with SMS option for 2FA' do visit_idp_from_saml_sp click_on 'Create an account' email_address = create_new_account_with_sms @@ -62,7 +62,7 @@ it 'creates new account with TOTP for 2FA' do visit_idp_from_saml_sp click_on 'Create an account' - email_address = create_new_account_with_totp + email_address, totp_secret = create_new_account_with_totp expect_user_is_redirected_to_saml_sp(email_address) diff --git a/spec/features/monitor/reset_password_spec.rb b/spec/features/monitor/reset_password_spec.rb index ca087673c7c..90a81bf00a8 100644 --- a/spec/features/monitor/reset_password_spec.rb +++ b/spec/features/monitor/reset_password_spec.rb @@ -6,13 +6,16 @@ before { monitor.setup } it 'resets password at LOA1' do + visit monitor.idp_signup_url + email_address, totp_secret = create_new_account_with_totp + page.first(:link, 'Sign out').click visit monitor.idp_reset_password_url - fill_in 'password_reset_email_form_email', with: monitor.config.login_gov_sign_in_email + fill_in 'password_reset_email_form_email', with: email_address click_on 'Continue' expect(page).to have_content('Check your email') - reset_link = monitor.check_for_password_reset_link + reset_link = monitor.check_for_password_reset_link(email_address) expect(reset_link).to be_present visit reset_link fill_in 'reset_password_form_password', with: monitor.config.login_gov_sign_in_password diff --git a/spec/features/monitor/sign_in_out_spec.rb b/spec/features/monitor/sign_in_out_spec.rb index 3e5fc1240e3..76dea2cd704 100644 --- a/spec/features/monitor/sign_in_out_spec.rb +++ b/spec/features/monitor/sign_in_out_spec.rb @@ -7,9 +7,9 @@ it 'creates account, signs out, signs back in' do visit monitor.idp_signup_url - creds = create_new_account_with_sms + email_address, totp_secret = create_new_account_with_totp page.first(:link, 'Sign out').click - sign_in_and_2fa(creds) + sign_in_and_2fa(email_address, totp_secret) expect(page).to have_content('Your account') expect(page.current_url).to include("#{monitor.config.idp_signin_url}/account") diff --git a/spec/features/monitor/sp_signin_spec.rb b/spec/features/monitor/sp_signin_spec.rb index 1e2c507d5e1..b2559ebdc16 100644 --- a/spec/features/monitor/sp_signin_spec.rb +++ b/spec/features/monitor/sp_signin_spec.rb @@ -10,8 +10,11 @@ before { monitor.filter_unless('STAGING') } it 'redirects back to SP' do + visit monitor.idp_signup_url + email_address, totp_secret = create_new_account_with_totp + page.first(:link, 'Sign out').click visit_idp_from_oidc_sp - sign_in_and_2fa(monitor.config.login_gov_sign_in_email) + sign_in_and_2fa(email_address, totp_secret) click_on 'Agree and continue' if on_consent_screen? @@ -30,14 +33,17 @@ before { monitor.filter_if('INT') } it 'redirects back to SP' do + visit monitor.idp_signup_url + email_address, totp_secret = create_new_account_with_totp + page.first(:link, 'Sign out').click visit_idp_from_saml_sp - sign_in_and_2fa(monitor.config.login_gov_sign_in_email) + sign_in_and_2fa(email_address, totp_secret) click_on 'Agree and continue' if on_consent_screen? if monitor.remote? expect(page).to have_content('SAML Sinatra Example') - expect(page).to have_content(monitor.config.login_gov_sign_in_email) + expect(page).to have_content(email_address) expect(current_url).to include(monitor.config.saml_sp_url) else click_on 'Submit' diff --git a/spec/support/monitor/monitor_config.rb b/spec/support/monitor/monitor_config.rb index 1e3482f47ce..71d76f5e287 100644 --- a/spec/support/monitor/monitor_config.rb +++ b/spec/support/monitor/monitor_config.rb @@ -10,8 +10,8 @@ def local? def check_env_variables! expected_env_vars = %w[ - MONITOR_EMAIL - MONITOR_EMAIL_PASSWORD + MONITOR_EMAIL_DOMAIN + MONITOR_EMAIL_S3_BUCKET MONITOR_GOOGLE_VOICE_PHONE MONITOR_SMS_SIGN_IN_EMAIL MONITOR_ENV @@ -27,12 +27,14 @@ def check_env_variables! raise message unless missing_env_vars.empty? end - # Gmail account name def email_address - ENV['MONITOR_EMAIL'] || 'test@example.com' + if ENV['MONITOR_EMAIL_DOMAIN'] && ENV['MONITOR_ENV'] + "smoketest-#{ENV['MONITOR_ENV'].downcase}@#{ENV['MONITOR_EMAIL_DOMAIN']}" + else + 'test@example.com' + end end - # Password for email_address Gmail account def email_password ENV['MONITOR_EMAIL_PASSWORD'] || 'salty pickles' end @@ -55,6 +57,15 @@ def login_gov_sign_in_password ENV['MONITOR_SMS_SIGN_IN_PASSWORD'] || 'salty pickles' end + # S3 bucket where emails are sent + def email_s3_bucket + ENV['MONITOR_EMAIL_S3_BUCKET'] + end + + def email_s3_prefix + ENV['MONITOR_EMAIL_S3_PREFIX'] || "inbound/smoketest-#{ENV['MONITOR_ENV'].to_s.downcase}/" + end + def monitor_env ENV['MONITOR_ENV'].to_s.upcase end diff --git a/spec/support/monitor/monitor_email_helper.rb b/spec/support/monitor/monitor_email_helper.rb index 9c1c7a1a0a6..64a71e6c471 100644 --- a/spec/support/monitor/monitor_email_helper.rb +++ b/spec/support/monitor/monitor_email_helper.rb @@ -1,10 +1,13 @@ -require 'gmail' +require 'aws-sdk-s3' +require 'mail' class MonitorEmailHelper - attr_reader :gmail + attr_reader :email - def initialize(email:, password:, local:) - @gmail = Gmail.connect!(email, password) unless local + def initialize(email:, local:, s3_bucket:, s3_prefix:) + @email = email + @s3_bucket = s3_bucket + @s3_prefix = s3_prefix @local = local end @@ -12,16 +15,33 @@ def local? @local end - def inbox_unread - gmail.inbox.emails(:unread) - end + def find_in_inbox(regex:, subjects:, email_address:) + s3 = Aws::S3::Client.new + objects = s3.list_objects(bucket: @s3_bucket, prefix: @s3_prefix, max_keys: 100). + contents.sort_by { |x| x.last_modified.to_i }.reverse + + objects.each do |x| + object = begin + s3.get_object(bucket: @s3_bucket, key: x.key) + rescue Aws::S3::Errors::AccessDenied + nil + end - def inbox_clear - inbox_unread.each(&:read!) - gmail.inbox.emails(:read).each(&:delete!) + next if object.nil? + body = object.body.read + mail = Mail.new(body) + next unless mail.to&.include?(email_address) + next unless subjects.blank? || subjects.include?(mail.subject) + match_data = mail.text_part.to_s.match(regex) + next unless match_data + s3.delete_object(bucket: @s3_bucket, key: x.key) + return match_data[1] + end + + nil end - def scan_emails_and_extract(regex:, subject: nil) + def scan_emails_and_extract(regex:, email_address:, subject: nil) subjects = [*subject] if local? @@ -31,17 +51,8 @@ def scan_emails_and_extract(regex:, subject: nil) end else check_and_sleep do - inbox_unread.each do |email| - if subjects.any? - next unless subjects.include?(email.subject) - end - body = email.message.parts.first.body - if (match_data = body.match(regex)) - email.read! - return match_data[1] - end - end - nil + result = find_in_inbox(regex: regex, subjects: subjects, email_address: email_address) + return result if result.present? end end diff --git a/spec/support/monitor/monitor_helper.rb b/spec/support/monitor/monitor_helper.rb index 8b223753874..2387b8e1e2c 100644 --- a/spec/support/monitor/monitor_helper.rb +++ b/spec/support/monitor/monitor_helper.rb @@ -19,8 +19,9 @@ def config def email @email ||= MonitorEmailHelper.new( email: config.email_address, - password: config.email_password, local: local?, + s3_bucket: config.email_s3_bucket, + s3_prefix: config.email_s3_prefix, ) end @@ -35,7 +36,6 @@ def setup else config.check_env_variables! reset_sessions - email.inbox_clear end end @@ -72,20 +72,22 @@ def reset_sessions Capybara.reset_session! end - def check_for_password_reset_link + def check_for_password_reset_link(email_address) email.scan_emails_and_extract( subject: 'Reset your password', regex: /(?https?:.+reset_password_token=[\w\-]+)/, + email_address: email_address, ) end - def check_for_confirmation_link + def check_for_confirmation_link(email_address) email.scan_emails_and_extract( subject: [ 'Confirm your email', 'Email not found', ], regex: /(?https?:.+confirmation_token=[\w\-]+)/, + email_address: email_address, ) end diff --git a/spec/support/monitor/monitor_idp_steps.rb b/spec/support/monitor/monitor_idp_steps.rb index 14173e605c3..8f696e1a97e 100644 --- a/spec/support/monitor/monitor_idp_steps.rb +++ b/spec/support/monitor/monitor_idp_steps.rb @@ -26,7 +26,7 @@ def create_new_account_up_until_password(email_address = random_email_address) fill_in 'user_email', with: email_address check 'user_terms_accepted' click_on 'Submit' - confirmation_link = monitor.check_for_confirmation_link + confirmation_link = monitor.check_for_confirmation_link(email_address) visit confirmation_link fill_in 'password_form_password', with: monitor.config.login_gov_sign_in_password submit_password @@ -53,7 +53,7 @@ def create_new_account_with_sms email_address end - def sign_in_and_2fa(email) + def sign_in_and_2fa(email, totp_secret) fill_in 'user_email', with: email fill_in 'user_password', with: monitor.config.login_gov_sign_in_password click_on 'Sign in' @@ -63,7 +63,9 @@ def sign_in_and_2fa(email) click_button 'Continue' end - fill_in 'code', with: monitor.check_for_otp + # TOTP codes can only be generated every 30 seconds, and we just generated one for signup + sleep(31) + fill_in 'code', with: generate_totp_code(totp_secret) uncheck 'Remember this browser' click_on 'Submit' end @@ -76,13 +78,14 @@ def create_new_account_with_totp secret = find('#qr-code').text fill_in 'name', with: 'Authentication app' fill_in 'code', with: generate_totp_code(secret) + uncheck 'Remember this browser' click_button 'Submit' if /two_factor_options_success/.match?(current_path) click_on 'Continue' setup_backup_codes end - email_address + [email_address, secret] end def generate_totp_code(secret) diff --git a/spec/support/monitor/monitor_idv_steps.rb b/spec/support/monitor/monitor_idv_steps.rb index 06aaf61c727..c2f3eb30edd 100644 --- a/spec/support/monitor/monitor_idv_steps.rb +++ b/spec/support/monitor/monitor_idv_steps.rb @@ -4,7 +4,7 @@ def verify_identity_with_doc_auth expect(page).to have_content 'You will also need' click_on 'Create an account' - create_new_account_with_sms + create_new_account_with_totp expect(page).to have_current_path('/verify/doc_auth/welcome') click_on 'Continue'