Skip to content
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
6 changes: 3 additions & 3 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
1 change: 0 additions & 1 deletion Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand Down
7 changes: 0 additions & 7 deletions Gemfile.lock
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -719,7 +713,6 @@ DEPENDENCIES
faker
faraday
foundation_emails
gmail (>= 0.7.1)
good_job (~> 2.2.0)
guard-rspec
hashie (~> 4.1)
Expand Down
8 changes: 4 additions & 4 deletions spec/features/monitor/create_account_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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'
Expand All @@ -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
Expand All @@ -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
Expand All @@ -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)

Expand Down
7 changes: 5 additions & 2 deletions spec/features/monitor/reset_password_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions spec/features/monitor/sign_in_out_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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")
Expand Down
12 changes: 9 additions & 3 deletions spec/features/monitor/sp_signin_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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?

Expand All @@ -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'
Expand Down
21 changes: 16 additions & 5 deletions spec/support/monitor/monitor_config.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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
Expand All @@ -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
Expand Down
55 changes: 33 additions & 22 deletions spec/support/monitor/monitor_email_helper.rb
Original file line number Diff line number Diff line change
@@ -1,27 +1,47 @@
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

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?
Expand All @@ -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

Expand Down
10 changes: 6 additions & 4 deletions spec/support/monitor/monitor_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand All @@ -35,7 +36,6 @@ def setup
else
config.check_env_variables!
reset_sessions
email.inbox_clear
end
end

Expand Down Expand Up @@ -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: /(?<link>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: /(?<link>https?:.+confirmation_token=[\w\-]+)/,
email_address: email_address,
)
end

Expand Down
11 changes: 7 additions & 4 deletions spec/support/monitor/monitor_idp_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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'
Expand All @@ -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)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

😭 😭 😭
Is it possible to generate one 30 seconds in the future and hope that our site allows some clock skew?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or maybe should we just do backup codes and save the backup codes in memory? This seems like a very long time to wait

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a bummer, but I don't super mind since smoke tests don't generally block PRs, and different environments can now run simultaneously

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's true! But if we ever have to test these manually to verify, 30 seconds feels like an eternity

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm open to switching to backup codes in this PR, but my feeling is to get something out now so smoke tests can start again

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Makes sense, I agree, probably better to ship something sooner

fill_in 'code', with: generate_totp_code(totp_secret)
uncheck 'Remember this browser'
click_on 'Submit'
end
Expand All @@ -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)
Expand Down
2 changes: 1 addition & 1 deletion spec/support/monitor/monitor_idv_steps.rb
Original file line number Diff line number Diff line change
Expand Up @@ -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'

Expand Down