Prevent reg lock bypass on alternate phone number forms

This commit is contained in:
Ameya Lokare 2026-04-14 14:24:38 -07:00 committed by Jon Chambers
parent 288b9f82d7
commit bb7d855aca
2 changed files with 38 additions and 1 deletions

View File

@ -136,7 +136,14 @@ public class RegistrationController {
final PhoneVerificationRequest.VerificationType verificationType =
phoneVerificationTokenManager.verify(requestContext, number, registrationRequest);
final Optional<Account> existingAccount = accounts.getByE164(number);
// There can be at most one existing account for a set of numbers in the same equivalence class, so it's sufficient
// to find the first one.
final Optional<Account> existingAccount = Util.getAlternateForms(number)
.stream()
.map(accounts::getByE164)
.filter(Optional::isPresent)
.map(Optional::get)
.findFirst();
existingAccount.ifPresent(account -> {
final Instant accountLastSeen = Instant.ofEpochMilli(account.getLastSeen());

View File

@ -441,6 +441,36 @@ class RegistrationControllerTest {
.argumentsForNextParameter(registrationLockErrors);
}
@Test
void registrationLockOnAlternatePhoneNumberForm() throws Exception {
final String newFormatBeninNumber = PhoneNumberUtil.getInstance()
.format(PhoneNumberUtil.getInstance().getExampleNumber("BJ"), PhoneNumberUtil.PhoneNumberFormat.E164);
final String oldFormatBeninNumber = newFormatBeninNumber.replaceFirst("01", "");
when(registrationServiceClient.getSession(any(), any()))
.thenReturn(
CompletableFuture.completedFuture(
Optional.of(new RegistrationServiceSession(new byte[16], newFormatBeninNumber, true, null, null, null,
SESSION_EXPIRATION_SECONDS))));
final Account account = mock(Account.class);
when(accountsManager.getByE164(oldFormatBeninNumber)).thenReturn(Optional.of(account));
when(accountsManager.getByE164(newFormatBeninNumber)).thenReturn(Optional.empty());
when(account.hasCapability(DeviceCapability.TRANSFER)).thenReturn(false);
doThrow(new WebApplicationException(RegistrationLockError.MISMATCH.getExpectedStatus()))
.when(registrationLockVerificationManager).verifyRegistrationLock(any(), any(), any(), any(), any());
final Invocation.Builder request = resources.getJerseyTest()
.target("/v1/registration")
.request()
.header(HttpHeaders.AUTHORIZATION, AuthHelper.getProvisioningAuthHeader(newFormatBeninNumber, PASSWORD));
try (final Response response = request.post(Entity.json(requestJson("sessionId")))) {
assertEquals(RegistrationLockError.MISMATCH.getExpectedStatus(), response.getStatus());
}
}
@ParameterizedTest
@CsvSource({