-
Notifications
You must be signed in to change notification settings - Fork 173
fix(mfa): match getAuthenticators by Authenticator.type field #998
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -124,16 +124,19 @@ public class MfaApiClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVA | |
| * ## Usage | ||
| * | ||
| * ```kotlin | ||
| * mfaClient.getAuthenticators(listOf("otp", "oob")) | ||
| * mfaClient.getAuthenticators(listOf("otp", "phone")) | ||
| * .start(object : Callback<List<Authenticator>, MfaListAuthenticatorsException> { | ||
| * override fun onSuccess(result: List<Authenticator>) { | ||
| * // Only OTP and OOB authenticators returned | ||
| * // Only authenticators whose `type` is "otp" or "phone" are returned | ||
| * } | ||
| * override fun onFailure(error: MfaListAuthenticatorsException) { } | ||
| * }) | ||
| * ``` | ||
| * | ||
| * @param factorsAllowed Array of factor types to filter the authenticators (e.g., `["otp", "oob", "recovery-code"]`). | ||
| * Filtering matches each authenticator's [Authenticator.type] field against the | ||
| * provided values using exact (case-sensitive) equality. | ||
| * | ||
| * @param factorsAllowed Array of factor types to filter the authenticators (e.g., `["otp", "phone", "email", "recovery-code"]`). | ||
| * Must contain at least one factor type. | ||
|
Comment on lines
+127
to
140
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🌐 Web query:
💡 Result: For phone or SMS-based authenticators in Auth0, the actual field returned by the GET /mfa/authenticators endpoint is Citations:
🏁 Script executed: #!/bin/bash
set -euo pipefail
# Locate the relevant client and test references.
git ls-files 'auth0/src/main/java/com/auth0/android/authentication/mfa/MfaApiClient.kt' \
'auth0/src/test/**/MfaApiClientTest.kt' \
'auth0/src/**/MfaApiClientTest.kt' \
'auth0/src/**/mfa/**' | sed 's#^`#-` #'
printf '\n== MfaApiClient.kt excerpt ==\n'
sed -n '110,155p' auth0/src/main/java/com/auth0/android/authentication/mfa/MfaApiClient.kt
printf '\n== Search for factor/type values in tests ==\n'
rg -n '"type"\s*:\s*"(oob|otp|phone|email|recovery-code)"|factorsAllowed|Authenticator.type|oob_channel|authenticator_type' auth0/src/test auth0/src/main -g '*MfaApiClientTest.kt' -g '*.kt'Repository: auth0/Auth0.Android Length of output: 8536 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Inspect the specific test regions mentioned by the review comment.
test_file=$(git ls-files 'auth0/src/test/**/MfaApiClientTest.kt' 'auth0/src/**/MfaApiClientTest.kt' | head -n 1)
if [ -z "$test_file" ]; then
echo "MfaApiClientTest.kt not found"
exit 0
fi
printf 'Using test file: %s\n' "$test_file"
for range in '240,270' '296,330' '340,390' '830,860'; do
printf '\n== %s lines %s ==\n' "$test_file" "$range"
sed -n "${range}p" "$test_file"
doneRepository: auth0/Auth0.Android Length of output: 6455 🏁 Script executed: #!/bin/bash
set -euo pipefail
# Read the surrounding code and nearby tests that define the expected factor values.
printf '\n== MfaApiClient.kt around the documented example ==\n'
sed -n '120,145p' auth0/src/main/java/com/auth0/android/authentication/mfa/MfaApiClient.kt
printf '\n== Search for API/model docs and test fixtures mentioning MFA authenticator types ==\n'
rg -n 'oob|otp|phone|email|recovery-code|authenticator_type|Authenticator.type|getAuthenticators' auth0/src/main/java auth0/src/test -g '*.kt'Repository: auth0/Auth0.Android Length of output: 50377 Use 🤖 Prompt for AI Agents |
||
| * @return a request to configure and start that will yield a list of [Authenticator] | ||
| * | ||
|
|
@@ -307,11 +310,11 @@ public class MfaApiClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVA | |
| * transparently by the SDK. | ||
| * | ||
| * **Filtering:** | ||
| * Authenticators are filtered by their effective type: | ||
| * - OOB authenticators: matched by their channel ("sms" or "email") | ||
| * - Other authenticators: matched by their type ("otp", "recovery-code", etc.) | ||
| * An authenticator is included when [Authenticator.type] exactly matches one of the | ||
| * provided [factorsAllowed] values (case-sensitive equality). This mirrors the | ||
| * filtering behavior of the Auth0.swift SDK. | ||
| * | ||
| * @param factorsAllowed List of factor types to include (e.g., ["sms", "email", "otp"]) | ||
| * @param factorsAllowed List of factor types to include (e.g., ["phone", "email", "otp"]) | ||
| * @return A JsonAdapter that produces a filtered list of authenticators | ||
| */ | ||
| private fun createFilteringAuthenticatorsAdapter(factorsAllowed: List<String>): JsonAdapter<List<Authenticator>> { | ||
|
|
@@ -321,66 +324,12 @@ public class MfaApiClient @VisibleForTesting(otherwise = VisibleForTesting.PRIVA | |
| val allAuthenticators = baseAdapter.fromJson(reader, metadata) | ||
|
|
||
| return allAuthenticators.filter { authenticator -> | ||
| matchesFactorType(authenticator, factorsAllowed) | ||
| factorsAllowed.contains(authenticator.type) | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Checks if an authenticator matches any of the allowed factor types. | ||
| * | ||
| * The matching logic handles various factor type aliases: | ||
| * - "sms" or "phone": matches OOB authenticators with SMS channel | ||
| * - "email": matches OOB authenticators with email channel | ||
| * - "otp" or "totp": matches time-based one-time password authenticators | ||
| * - "oob": matches any out-of-band authenticator regardless of channel | ||
| * - "recovery-code": matches recovery code authenticators | ||
| * - "push-notification": matches push notification authenticators | ||
| * | ||
| * @param authenticator The authenticator to check | ||
| * @param factorsAllowed List of allowed factor types | ||
| * @return true if the authenticator matches any allowed factor type | ||
| */ | ||
| private fun matchesFactorType( | ||
| authenticator: Authenticator, | ||
| factorsAllowed: List<String> | ||
| ): Boolean { | ||
| val effectiveType = getEffectiveType(authenticator) | ||
|
|
||
| return factorsAllowed.any { factor -> | ||
| val normalizedFactor = factor.lowercase(java.util.Locale.ROOT) | ||
| when (normalizedFactor) { | ||
| "sms", "phone" -> effectiveType == "sms" || effectiveType == "phone" | ||
| "email" -> effectiveType == "email" | ||
| "otp", "totp" -> effectiveType == "otp" || effectiveType == "totp" | ||
| "oob" -> authenticator.authenticatorType == "oob" || authenticator.type == "oob" | ||
| "recovery-code" -> effectiveType == "recovery-code" | ||
| "push-notification" -> effectiveType == "push-notification" | ||
| else -> effectiveType == normalizedFactor || | ||
| authenticator.authenticatorType?.lowercase(java.util.Locale.ROOT) == normalizedFactor || | ||
| authenticator.type.lowercase(java.util.Locale.ROOT) == normalizedFactor | ||
| } | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Resolves the effective type of an authenticator for filtering purposes. | ||
| * | ||
| * OOB (out-of-band) authenticators use their channel ("sms" or "email") as the | ||
| * effective type, since users typically filter by delivery method rather than | ||
| * the generic "oob" type. Other authenticators use their authenticatorType directly. | ||
| * | ||
| * @param authenticator The authenticator to get the type for | ||
| * @return The effective type string used for filtering | ||
| */ | ||
| private fun getEffectiveType(authenticator: Authenticator): String { | ||
| return when (authenticator.authenticatorType) { | ||
| "oob" -> authenticator.oobChannel ?: "oob" | ||
| else -> authenticator.authenticatorType ?: authenticator.type | ||
| } | ||
| } | ||
|
|
||
| /** | ||
| * Helper function for OOB enrollment (SMS, email, push). | ||
| */ | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.