Testing a MFA Integration

Security for large organisations is paramount in today's online world, especially for systems that rely on users to remember passwords and passcodes to sign into all their products and services.

We’ve found that by integrating a third-party authentication service with an organisation, once the initial integration work has been done, the organisation can benefit from many high-level security features without any additional development effort.

That being said, automated testing the integration with a third party authentication service is where things can get tricky.

In this project Overloop provided the test automation for an integration with Auth0.com.

The most difficult part of testing this integration was how to test the steps that the user has to perform to complete login. Unlike the more usual automated web testing where we simulate a user clicking on links and entering data into text boxes on a web page, rather the steps we have to automate here are things like ‘scan a QR code’, ‘receive an SMS message’. Our automated tests have to impersonate these steps in order to test the whole process end-to-end.

For our use case we had to support logins by new users who would register with Auth0 from the start, but we also had to support existing users who were being migrated from the old user authentication setup to the new Auth0 based setup.

To support this here are the main MFA(multi-factor authentication) scenarios that we considered:

  • A user should be able to login to the system using the MFA service (needs user interaction to enter a one time password)

  • An existing user should be able to migrate to the MFA service (needs user interaction to verify account, register an MFA device and enter a one time password)

  • A new user should be able to register with the MFA service (needs user interaction to reset the password, register a new MFA device and enter a one time password)

  • A user who has multiple accounts should be able to activate single-sign on for the MFA service (needs user interaction to activate SSO)

  • A user should be able to reset their password (needs user interaction to reset password)

As some of these scenarios involve running client-specific code and configuration inside auth0, we decided to have the automated tests cover the whole user journey including the steps through Auth0 screens:

Automated testing blog post - Page 3 (1).png

This diagram is the user journey for an existing user who is migrating to Auth0:

 
Automated testing blog post - Page 2.png
 

We have to provide a flow for users to migrate through the Auth0 service and register an MFA device to authenticate themselves. As you can see from the diagram above, there are 3 steps that need tricky user interaction to move forward with the flow.

  1. The user will receive an email which contains a verification link that they need to click on

  2. The user needs to configure an MFA method

    a. They can choose to use an OTP Authenticator app (can be Guardian application provided by Auth0 or Google authenticator app)

    b. Or they can choose to receive SMS text messages (provided by Twilio)

  3. The user needs to enter the One Time Password (OTP) into Auth0 to complete the migration and login process

The easiest way to test these methods of authentication is to register one unique users per MFA method and to automate the login process.

To start off with, we are using a tool like Selenium to click our way through the Auth0 login screens. The user is asked to provide their email address, which then leads to a screen that looks like this:

 
9.png
 

So we need an automated way to read that email as it has a link in it that we need to visit.


1 User verification via email

To read the email that contains the verification link we create a custom email rule on AWS using the Simple Email Service (SES) for an email address that will send all emails received on that email address as text files in an S3 bucket. So for example we would set up an email address like ‘auth0@overloop.io’.


1. In AWS Find SES service

2. From the menu on the left side click on Rule Sets

3. Click on Create a Rule Set

Screenshot 2019-05-28 at 15.42.06.png

4. Give a name to the rule set

5. Click on the new rule set

6. Click on Create Rule

7. Add a recipient

8. Add an action

9. Create rule

Screenshot 2019-05-28 at 15.45.00.png

This will cause a file to be written to S3 every time an email is received on auth0@overloop.io. This will only work if the email service on the domain is managed by AWS SES.

Using a Ruby S3 Client, gem"aws-sdk", "2.8.9",  we read the email content from the bucket:

email_content = Support::S3Client.read_file(
   bucket: "auth0",
   prefix: "auth0"
 )

From email content we extracting the verification link using a regex:

URI.extract(email_content.partition("Visit this link").last.unpack("M").to_s)

The regex used depends on the content of the email. Unpack(“M”) is needed to decode the quoted-printable encoding used on emails.

Example of extracted url

https://qa-client.auth0.com/lo/verify_email?ticket=abc123#

We then use a tool like Selenium to visit that URL which gets us the login page for the user. The user now has to choose the MFA method, either an OTP authenticator app or SMS.

 
1 copy.png
 

2a OTP Authenticator App

 
2 copy 1.png
 

To test the OTP Authenticator App option, we will simulate a user clicking on the ‘Google Authenticator’ link. This will result in the user getting a QR code from Auth0.

The QR code is served up by an Auth0 web page.

 
3 copy.png
 

Within that webpage there is an <img> element that contains the otpauth URI, which includes a query string param ‘secret’, which can be extracted so we can generate an OTP password. For someone new to OTP we recommend this link on how TOTP works:

https://github.com/google/google-authenticator/wiki/Key-Uri-Format

It will explain how the query string in the path of the image contains the secret that can be used to generate the OTP.

So we are looking for an <img> element that includes this param:

otpauth://totp/IIJ:iij-taro@example.com?secret=SOME_SECRET1234567890&issuer=IIJ

We used the Ruby library  gem "rotp", "3.3.1" to generate an OTP:

       def generate_otp(secret)
         ROTP::TOTP.new(secret).now
       end


That gives us a 6-digit OTP code.

We then use Selenium, to enter the code we have generated into the text box:

 
4 copy.png
 

2b SMS

We simulate the user journey through the pages but this time we click on the ‘SMS link to choose the SMS:

 
2 copy.png
 
 
6 copy.png
 

Using a Ruby Twilio Client (gem"twilio-ruby", "5.15.2"), to read the sms received to a specific phone number

     def read_sms_code(phone_number:)
       code = ""
       wait_for_sms(phone_number: phone_number)
       @messages = twilio_client.messages.list(
         to: phone_number
       )
       @messages.each do |message|
         # SMS code is in 6 digit format, using regex to extract it
         code = message.body.scan(/\b\d\b/)
         break
       end
       code
     End


We extract the 6-digit OTP code from the SMS and enter  it into a text box on the Auth0 page:

 
7 copy.png
 

3 Successful Authentication

After we have successfully entered the 6-digit OTP code we are authenticated and redirecting to Client Application

 
8 copy.png