Skip to content

Ensure attempt to complete a verification method is allowed

What does this MR do and why?

In preparation for https://gitlab.com/gitlab-org/modelops/anti-abuse/team-tasks/-/issues/542+, this ensures attempt to complete a verification method is allowed.

Context: users are required to complete verification methods in order depending on their risk score:

Risk score Required verification methods (in order)
Low 1. email
Medium 1. email 2. phone
High 1. email 2. phone 3. credit card

Previously, phone number verification endpoints were secured (using a before action hook) by ensuring that a user is required to complete phone number verification and has already completed email verification.

In this MR, the before action hook is made generic so it can ensure that a verification method is required and all its prerequisite verification methods are completed before the corresponding action is executed.

For example, if a user is required to complete the following:

Note: that the order of credit card and phone are swapped. This should not matter.

  1. email
  2. credit card
  3. phone

Hitting the credit card verification endpoints will require email method is completed and that credit card verification is actually required for the user. The same happens for phone number verification endpoints except for a slight difference: instead of just email method, completion of both email and credit card methods are checked.

How to set up and validate locally

Click to expand
  1. Enable the relevant feature flags

    > Feature.enable(:arkose_labs_signup_challenge)
    > Feature.enable(:identity_verification_phone_number)
    > Feature.enable(:identity_verification_credit_card)
    > Feature.enable(:identity_verification)
  2. Configure application settings for Identity Verification

    > ApplicationSetting.first.update(email_confirmation_setting: 'hard')
    > ApplicationSetting.first.update(arkose_labs_public_api_key: "XXX", arkose_labs_private_api_key: "YYY", require_admin_approval_after_user_signup: false)
    > ApplicationSetting.first.update(telesign_customer_xid: 'XXX', telesign_api_key: 'YYY')

    Note: credentials are in 1Password under Telesign API keys (development) and ArkoseLabs API keys (development)

  3. Register a new user

  4. Force user to have high risk

    > User.last.custom_attributes.by_key('arkose_risk_band').first.update!(value: 'High')
  5. Login with the new user

  6. Inspect the page and copy the CSRF token value as well as the session token key and values

    Click to expand Screenshot_2023-12-04_at_1.15.47_PM

    Screenshot_2023-12-04_at_1.18.02_PM

  7. Tail the logs

    tail -f log/application_json.log
  8. cURL the credit card verification endpoint with the CSRF token and session cookie key and values

    # example: curl 'http://localhost:3000/users/identity_verification/verify_credit_card' -H 'X-CSRF-Token: AcASKvAh5fs1iN3Gdm4mUyN6bd0JZ_cHP9wDZinLNQVcAPq_l-xYu3PvuZ5-gCfab1Zq6VlqUBWmyvvq890hZg' -H 'Content-Type: application/json' -H 'Cookie: _gitlab_session_0d0184310be27aaaec4eedf3c05ef650b389e2b1f09bc0cf7ce1d212eae05729=883b39b4a674e7cae77398deb0b4381d' -H 'Sec-Fetch-Mode: cors' -H 'Sec-Fetch-Site: same-origin'
    curl 'http://localhost:3000/users/identity_verification/verify_credit_card' -H 'X-CSRF-Token: <CSRF_TOKEN>' -H 'Content-Type: application/json' -H 'Cookie: <SESSION_COOKIE_KEY>=<SESSION_COOKIE_VALUE>' -H 'Sec-Fetch-Mode: cors' -H 'Sec-Fetch-Site: same-origin'
  9. Verify that you get {}% response and the following entry is logged

    {"severity":"INFO",..."meta.caller_id":"Users::IdentityVerificationController#verify_credit_card",..."message":"IdentityVerification::CreditCard","event":"Failed Attempt","action":"verify_credit_card"..."reason":"unauthorized"...}
  10. cURL the phone number send code endpoint with the CSRF token and session cookie key and values

    curl 'http://localhost:3000/users/identity_verification/send_phone_verification_code' -X POST -H 'X-CSRF-Token: <CSRF_TOKEN>' -H 'Content-Type: application/json' -H 'Cookie: <SESSION_COOKIE_KEY>=<SESSION_COOKIE_VALUE>' -H 'Sec-Fetch-Mode: cors' -H 'Sec-Fetch-Site: same-origin' --data-raw '{}'
  11. Verify that you get {}% response and the following entry is logged

    {"severity":"INFO",..."meta.caller_id":"Users::IdentityVerificationController#send_phone_verification_code",..."message":"IdentityVerification::Phone","event":"Failed Attempt","action":"send_phone_verification_code"..."reason":"unauthorized"...}
  12. cURL the phone number verify code endpoint with the CSRF token and session cookie key and values

    curl 'http://localhost:3000/users/identity_verification/verify_phone_verification_code' -X POST -H 'X-CSRF-Token: <CSRF_TOKEN>' -H 'Content-Type: application/json' -H 'Cookie: <SESSION_COOKIE_KEY>=<SESSION_COOKIE_VALUE>' -H 'Sec-Fetch-Mode: cors' -H 'Sec-Fetch-Site: same-origin' --data-raw '{}'
  13. Verify that you get {}% response and the following entry is logged

       {"severity":"INFO",..."meta.caller_id":"Users::IdentityVerificationController#verify_phone_verification_code",..."message":"IdentityVerification::Phone","event":"Failed Attempt","action":"verify_phone_verification_code"..."reason":"unauthorized"...}

MR acceptance checklist

This checklist encourages us to confirm any changes have been analyzed to reduce risks in quality, performance, reliability, security, and maintainability.

Edited by Eugie Limpin

Merge request reports