mirror of
https://github.com/google/nomulus
synced 2025-12-23 06:15:42 +00:00
Make domain update flow handle null auth data (#2530)
It's valid for the auth data to be null (although it only happens 10 times across our entire registry), so the domain update flow should not fail out with a NullPointerException when the existing state of the data is null and the update isn't adding that data either. BUG=http://b/359264787
This commit is contained in:
@@ -14,7 +14,6 @@
|
||||
|
||||
package google.registry.flows.domain;
|
||||
|
||||
import static com.google.common.base.MoreObjects.firstNonNull;
|
||||
import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.collect.ImmutableSortedSet.toImmutableSortedSet;
|
||||
import static com.google.common.collect.Sets.symmetricDifference;
|
||||
@@ -282,7 +281,7 @@ public final class DomainUpdateFlow implements MutatingFlow {
|
||||
.removeContacts(remove.getContacts())
|
||||
.addContacts(add.getContacts())
|
||||
.setRegistrant(determineUpdatedRegistrant(change, domain))
|
||||
.setAuthInfo(firstNonNull(change.getAuthInfo(), domain.getAuthInfo()));
|
||||
.setAuthInfo(Optional.ofNullable(change.getAuthInfo()).orElse(domain.getAuthInfo()));
|
||||
|
||||
if (!add.getNameservers().isEmpty()) {
|
||||
domainBuilder.addNameservers(add.getNameservers().stream().collect(toImmutableSet()));
|
||||
|
||||
@@ -144,6 +144,7 @@ public class DomainBase extends EppResource
|
||||
@AttributeOverride(name = "pw.value", column = @Column(name = "auth_info_value")),
|
||||
@AttributeOverride(name = "pw.repoId", column = @Column(name = "auth_info_repo_id")),
|
||||
})
|
||||
@Nullable
|
||||
DomainAuthInfo authInfo;
|
||||
|
||||
/** Data used to construct DS records for this domain. */
|
||||
@@ -620,6 +621,7 @@ public class DomainBase extends EppResource
|
||||
return getAllContacts(true);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public DomainAuthInfo getAuthInfo() {
|
||||
return authInfo;
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ package google.registry.model.eppcommon;
|
||||
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.model.UnsafeSerializable;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.Embeddable;
|
||||
import javax.persistence.Embedded;
|
||||
import javax.persistence.MappedSuperclass;
|
||||
@@ -49,10 +50,12 @@ public abstract class AuthInfo extends ImmutableObject implements UnsafeSerializ
|
||||
public static class PasswordAuth extends ImmutableObject implements UnsafeSerializable {
|
||||
@XmlValue
|
||||
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)
|
||||
@Nullable
|
||||
String value;
|
||||
|
||||
@XmlAttribute(name = "roid")
|
||||
@XmlJavaTypeAdapter(CollapsedStringAdapter.class)
|
||||
@Nullable
|
||||
String repoId;
|
||||
|
||||
public String getValue() {
|
||||
@@ -63,14 +66,14 @@ public abstract class AuthInfo extends ImmutableObject implements UnsafeSerializ
|
||||
return repoId;
|
||||
}
|
||||
|
||||
public static PasswordAuth create(String value, String repoId) {
|
||||
public static PasswordAuth create(@Nullable String value, @Nullable String repoId) {
|
||||
PasswordAuth instance = new PasswordAuth();
|
||||
instance.value = value;
|
||||
instance.repoId = repoId;
|
||||
return instance;
|
||||
}
|
||||
|
||||
public static PasswordAuth create(String value) {
|
||||
public static PasswordAuth create(@Nullable String value) {
|
||||
return create(value, null);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -104,8 +104,10 @@ import google.registry.model.contact.Contact;
|
||||
import google.registry.model.domain.DesignatedContact;
|
||||
import google.registry.model.domain.DesignatedContact.Type;
|
||||
import google.registry.model.domain.Domain;
|
||||
import google.registry.model.domain.DomainAuthInfo;
|
||||
import google.registry.model.domain.DomainHistory;
|
||||
import google.registry.model.domain.secdns.DomainDsData;
|
||||
import google.registry.model.eppcommon.AuthInfo.PasswordAuth;
|
||||
import google.registry.model.eppcommon.Trid;
|
||||
import google.registry.model.host.Host;
|
||||
import google.registry.model.poll.PendingActionNotificationResponse.DomainPendingActionNotificationResponse;
|
||||
@@ -264,6 +266,38 @@ class DomainUpdateFlowTest extends ResourceFlowTestCase<DomainUpdateFlow, Domain
|
||||
doSuccessfulTest("generic_success_response_no_cltrid.xml");
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_noExistingAuthData() throws Exception {
|
||||
setEppInput("domain_update_no_auth_change.xml");
|
||||
persistReferencedEntities();
|
||||
persistDomain();
|
||||
persistResource(
|
||||
reloadResourceByForeignKey()
|
||||
.asBuilder()
|
||||
.setAuthInfo(DomainAuthInfo.create(PasswordAuth.create(null)))
|
||||
.build());
|
||||
assertMutatingFlow(true);
|
||||
runFlowAssertResponse(loadFile("generic_success_response.xml"));
|
||||
Domain domain = reloadResourceByForeignKey();
|
||||
// Check that the domain was updated. These values came from the xml.
|
||||
assertAboutDomains()
|
||||
.that(domain)
|
||||
.hasStatusValue(CLIENT_HOLD)
|
||||
.and()
|
||||
.hasAuthInfoPwd(null)
|
||||
.and()
|
||||
.hasOneHistoryEntryEachOfTypes(DOMAIN_CREATE, DOMAIN_UPDATE)
|
||||
.and()
|
||||
.hasLastEppUpdateTime(clock.nowUtc())
|
||||
.and()
|
||||
.hasLastEppUpdateRegistrarId("TheRegistrar")
|
||||
.and()
|
||||
.hasNoAutorenewEndTime();
|
||||
assertNoBillingEvents();
|
||||
assertDomainDnsRequests("example.tld");
|
||||
assertLastHistoryContainsResource(reloadResourceByForeignKey());
|
||||
}
|
||||
|
||||
@Test
|
||||
void testSuccess_cachingDisabled() throws Exception {
|
||||
boolean origIsCachingEnabled = RegistryConfig.isEppResourceCachingEnabled();
|
||||
|
||||
@@ -29,6 +29,7 @@ import google.registry.model.eppcommon.AuthInfo;
|
||||
import google.registry.testing.TruthChainer.And;
|
||||
import google.registry.tmch.LordnTaskUtils.LordnPhase;
|
||||
import java.util.Set;
|
||||
import javax.annotation.Nullable;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/** Truth subject for asserting things about {@link Domain} instances. */
|
||||
@@ -65,7 +66,7 @@ public final class DomainSubject extends AbstractEppResourceSubject<Domain, Doma
|
||||
return hasValue(lordnPhase, actual.getLordnPhase(), "lordnPhase");
|
||||
}
|
||||
|
||||
public And<DomainSubject> hasAuthInfoPwd(String pw) {
|
||||
public And<DomainSubject> hasAuthInfoPwd(@Nullable String pw) {
|
||||
AuthInfo authInfo = actual.getAuthInfo();
|
||||
return hasValue(pw, authInfo == null ? null : authInfo.getPw().getValue(), "has auth info pw");
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
<epp xmlns="urn:ietf:params:xml:ns:epp-1.0">
|
||||
<command>
|
||||
<update>
|
||||
<domain:update
|
||||
xmlns:domain="urn:ietf:params:xml:ns:domain-1.0">
|
||||
<domain:name>example.tld</domain:name>
|
||||
<domain:add>
|
||||
<domain:ns>
|
||||
<domain:hostObj>ns2.example.foo</domain:hostObj>
|
||||
</domain:ns>
|
||||
<domain:contact type="tech">mak21</domain:contact>
|
||||
<domain:status s="clientHold"
|
||||
lang="en">Payment overdue.</domain:status>
|
||||
</domain:add>
|
||||
<domain:rem>
|
||||
<domain:ns>
|
||||
<domain:hostObj>ns1.example.foo</domain:hostObj>
|
||||
</domain:ns>
|
||||
<domain:contact type="tech">sh8013</domain:contact>
|
||||
<domain:status s="clientUpdateProhibited"/>
|
||||
</domain:rem>
|
||||
</domain:update>
|
||||
</update>
|
||||
<clTRID>ABC-12345</clTRID>
|
||||
</command>
|
||||
</epp>
|
||||
Reference in New Issue
Block a user