diff --git a/core/src/main/java/google/registry/model/registrar/Registrar.java b/core/src/main/java/google/registry/model/registrar/Registrar.java index 3f44cfe4a..ed7531d92 100644 --- a/core/src/main/java/google/registry/model/registrar/Registrar.java +++ b/core/src/main/java/google/registry/model/registrar/Registrar.java @@ -22,6 +22,7 @@ import static com.google.common.base.Strings.nullToEmpty; import static com.google.common.collect.ImmutableSet.toImmutableSet; import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet; import static com.google.common.collect.Sets.immutableEnumSet; +import static com.google.common.collect.Streams.stream; import static com.google.common.io.BaseEncoding.base64; import static google.registry.config.RegistryConfig.getDefaultRegistrarWhoisServer; import static google.registry.model.CacheUtils.memoizeWithShortExpiration; @@ -794,6 +795,24 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J } } + // Making sure there's no registrar with the same ianaId already in the system + private static boolean isNotADuplicateIanaId( + Iterable registrars, Registrar newInstance) { + // Return early if newly build registrar is not type REAL or ianaId is + // reserved by ICANN - https://www.iana.org/assignments/registrar-ids/registrar-ids.xhtml + if (!Type.REAL.equals(newInstance.type) + || ImmutableSet.of(1L, 8L).contains(newInstance.ianaIdentifier)) { + return true; + } + + return stream(registrars) + .filter(registrar -> Type.REAL.equals(registrar.getType())) + .filter(registrar -> !Objects.equals(newInstance.registrarId, registrar.getRegistrarId())) + .noneMatch( + registrar -> + Objects.equals(newInstance.ianaIdentifier, registrar.getIanaIdentifier())); + } + public Builder setContactsRequireSyncing(boolean contactsRequireSyncing) { getInstance().contactsRequireSyncing = contactsRequireSyncing; return this; @@ -912,6 +931,15 @@ public class Registrar extends UpdateAutoTimestampEntity implements Buildable, J "Supplied IANA ID is not valid for %s registrar type: %s", getInstance().type, getInstance().ianaIdentifier)); + // We do not allow creating Real registrars with IANA ID that's already in the system + // b/315007360 - for more details + checkArgument( + isNotADuplicateIanaId(loadAllCached(), getInstance()), + String.format( + "Rejected attempt to create a registrar with ianaId that's already in the system -" + + " %s", + getInstance().ianaIdentifier)); + // In order to grant access to real TLDs, the registrar must have a corresponding billing // account ID for that TLD's billing currency. ImmutableSet nonBillableTlds = diff --git a/core/src/test/java/google/registry/model/registrar/RegistrarTest.java b/core/src/test/java/google/registry/model/registrar/RegistrarTest.java index aeccc5703..08fb74fb3 100644 --- a/core/src/test/java/google/registry/model/registrar/RegistrarTest.java +++ b/core/src/test/java/google/registry/model/registrar/RegistrarTest.java @@ -201,6 +201,23 @@ class RegistrarTest extends EntityTestCase { () -> new Registrar.Builder().setRegistrarId("abcdefghijklmnopq")); } + @Test + void testFailure_duplicateIanaId() { + persistResource( + registrar.asBuilder().setRegistrarId("registrar1").setIanaIdentifier(10L).build()); + + IllegalArgumentException thrown = + assertThrows( + IllegalArgumentException.class, + () -> + registrar.asBuilder().setRegistrarId("registrar2").setIanaIdentifier(10L).build()); + + assertThat(thrown) + .hasMessageThat() + .contains( + "Rejected attempt to create a registrar with ianaId that's already in the system"); + } + @Test void testSetCertificateHash_alsoSetsHash() { registrar = registrar.asBuilder().setClientCertificate(null, fakeClock.nowUtc()).build(); diff --git a/core/src/test/java/google/registry/testing/DatabaseHelper.java b/core/src/test/java/google/registry/testing/DatabaseHelper.java index c0a5a7947..232670717 100644 --- a/core/src/test/java/google/registry/testing/DatabaseHelper.java +++ b/core/src/test/java/google/registry/testing/DatabaseHelper.java @@ -778,7 +778,7 @@ public final class DatabaseHelper { /** Persists and returns a {@link Registrar} with the specified registrarId. */ public static Registrar persistNewRegistrar(String registrarId) { - return persistNewRegistrar(registrarId, registrarId + " name", Registrar.Type.REAL, 100L); + return persistNewRegistrar(registrarId, registrarId + " name", Registrar.Type.REAL, 8L); } /** Persists and returns a list of {@link Registrar}s with the specified registrarIds. */