mirror of
https://github.com/google/nomulus.git
synced 2025-07-09 04:33:28 +02:00
Add a RelockDomainAction for future auto-relocks (#485)
* Add a RelockAction and reference to relocks in RegistryLocks * Respond to CR - refactor the request param exception logging a bit - don't log an error if the domain was already locked, just skip * Save a relock for all locks (if possible) * derp * Long -> long + remove unnecessary transact * semantic merge conflict woo * fix another semantic merge conflict
This commit is contained in:
parent
3e7ea75b6f
commit
560bec1e83
17 changed files with 578 additions and 41 deletions
|
@ -0,0 +1,176 @@
|
|||
// Copyright 2020 The Nomulus Authors. All Rights Reserved.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package google.registry.batch;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.eppcommon.StatusValue.PENDING_DELETE;
|
||||
import static google.registry.model.eppcommon.StatusValue.PENDING_TRANSFER;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.testing.DatastoreHelper.createTlds;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainBase;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatastoreHelper.persistDomainAsDeleted;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.SqlHelper.getMostRecentVerifiedRegistryLockByRepoId;
|
||||
import static google.registry.testing.SqlHelper.getRegistryLockByVerificationCode;
|
||||
import static google.registry.testing.SqlHelper.saveRegistryLock;
|
||||
import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STATUSES;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.schema.domain.RegistryLock;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.DeterministicStringGenerator;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.testing.UserInfo;
|
||||
import google.registry.tools.DomainLockUtils;
|
||||
import google.registry.util.StringGenerator.Alphabets;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
/** Unit tests for {@link RelockDomainAction}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class RelockDomainActionTest {
|
||||
|
||||
private static final String DOMAIN_NAME = "example.tld";
|
||||
private static final String CLIENT_ID = "TheRegistrar";
|
||||
private static final String POC_ID = "marla.singer@example.com";
|
||||
|
||||
private final FakeResponse response = new FakeResponse();
|
||||
private final FakeClock clock = new FakeClock();
|
||||
private final DomainLockUtils domainLockUtils =
|
||||
new DomainLockUtils(new DeterministicStringGenerator(Alphabets.BASE_58));
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngineRule =
|
||||
AppEngineRule.builder()
|
||||
.withDatastoreAndCloudSql()
|
||||
.withUserService(UserInfo.create(POC_ID, "12345"))
|
||||
.build();
|
||||
|
||||
private DomainBase domain;
|
||||
private RegistryLock oldLock;
|
||||
private RelockDomainAction action;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
createTlds("tld", "net");
|
||||
HostResource host = persistActiveHost("ns1.example.net");
|
||||
domain = persistResource(newDomainBase(DOMAIN_NAME, host));
|
||||
|
||||
oldLock = domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, CLIENT_ID, POC_ID, false);
|
||||
assertThat(reloadDomain(domain).getStatusValues())
|
||||
.containsAtLeastElementsIn(REGISTRY_LOCK_STATUSES);
|
||||
oldLock = domainLockUtils.administrativelyApplyUnlock(DOMAIN_NAME, CLIENT_ID, false);
|
||||
assertThat(reloadDomain(domain).getStatusValues()).containsNoneIn(REGISTRY_LOCK_STATUSES);
|
||||
action = createAction(oldLock.getRevisionId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLock() {
|
||||
action.run();
|
||||
assertThat(reloadDomain(domain).getStatusValues())
|
||||
.containsAtLeastElementsIn(REGISTRY_LOCK_STATUSES);
|
||||
|
||||
// the old lock should have a reference to the relock
|
||||
RegistryLock newLock = getMostRecentVerifiedRegistryLockByRepoId(domain.getRepoId()).get();
|
||||
assertThat(getRegistryLockByVerificationCode(oldLock.getVerificationCode()).get().getRelock())
|
||||
.isEqualTo(newLock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unknownCode() {
|
||||
action = createAction(12128675309L);
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
|
||||
assertThat(response.getPayload()).isEqualTo("Relock failed: Unknown revision ID 12128675309");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_pendingDelete() {
|
||||
persistResource(domain.asBuilder().setStatusValues(ImmutableSet.of(PENDING_DELETE)).build());
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo(String.format("Relock failed: Domain %s has a pending delete", DOMAIN_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_pendingTransfer() {
|
||||
persistResource(domain.asBuilder().setStatusValues(ImmutableSet.of(PENDING_TRANSFER)).build());
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo(String.format("Relock failed: Domain %s has a pending transfer", DOMAIN_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainAlreadyLocked() {
|
||||
domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, CLIENT_ID, null, true);
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo("Domain example.tld is already manually relocked, skipping automated relock.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainDeleted() {
|
||||
persistDomainAsDeleted(domain, clock.nowUtc());
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo(String.format("Relock failed: Domain %s has been deleted", DOMAIN_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainTransferred() {
|
||||
persistResource(domain.asBuilder().setPersistedCurrentSponsorClientId("NewRegistrar").build());
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo(
|
||||
String.format(
|
||||
"Relock failed: Domain %s has been transferred from registrar %s to registrar "
|
||||
+ "%s since the unlock",
|
||||
DOMAIN_NAME, CLIENT_ID, "NewRegistrar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_relockAlreadySet() {
|
||||
RegistryLock newLock =
|
||||
domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, CLIENT_ID, null, true);
|
||||
saveRegistryLock(oldLock.asBuilder().setRelock(newLock).build());
|
||||
// Save the domain without the lock statuses so that we pass that check in the action
|
||||
persistResource(domain.asBuilder().setStatusValues(ImmutableSet.of()).build());
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo("Domain example.tld is already manually relocked, skipping automated relock.");
|
||||
}
|
||||
|
||||
private DomainBase reloadDomain(DomainBase domain) {
|
||||
return ofy().load().entity(domain).now();
|
||||
}
|
||||
|
||||
private RelockDomainAction createAction(Long oldUnlockRevisionId) {
|
||||
return new RelockDomainAction(oldUnlockRevisionId, domainLockUtils, response);
|
||||
}
|
||||
}
|
|
@ -18,7 +18,9 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
|||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.testing.SqlHelper.getMostRecentRegistryLockByRepoId;
|
||||
import static google.registry.testing.SqlHelper.getMostRecentUnlockedRegistryLockByRepoId;
|
||||
import static google.registry.testing.SqlHelper.getMostRecentVerifiedRegistryLockByRepoId;
|
||||
import static google.registry.testing.SqlHelper.getRegistryLockByRevisionId;
|
||||
import static google.registry.testing.SqlHelper.getRegistryLockByVerificationCode;
|
||||
import static google.registry.testing.SqlHelper.getRegistryLocksByRegistrarId;
|
||||
import static google.registry.testing.SqlHelper.saveRegistryLock;
|
||||
|
@ -121,6 +123,20 @@ public final class RegistryLockDaoTest {
|
|||
assertThat(getRegistryLockByVerificationCode("hi").isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByRevisionId_valid() {
|
||||
RegistryLock lock = saveRegistryLock(createLock());
|
||||
RegistryLock otherLock = getRegistryLockByRevisionId(lock.getRevisionId()).get();
|
||||
// can't do direct comparison due to update time
|
||||
assertThat(lock.getDomainName()).isEqualTo(otherLock.getDomainName());
|
||||
assertThat(lock.getVerificationCode()).isEqualTo(otherLock.getVerificationCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByRevisionId_invalid() {
|
||||
assertThat(getRegistryLockByRevisionId(8675309L).isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoad_lockedDomains_byRegistrarId() {
|
||||
RegistryLock lock = createLock();
|
||||
|
@ -192,6 +208,30 @@ public final class RegistryLockDaoTest {
|
|||
assertThat(mostRecent.isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoad_verifiedUnlock_byRepoId() {
|
||||
RegistryLock lock =
|
||||
saveRegistryLock(
|
||||
createLock()
|
||||
.asBuilder()
|
||||
.setLockCompletionTimestamp(fakeClock.nowUtc())
|
||||
.setUnlockRequestTimestamp(fakeClock.nowUtc())
|
||||
.setUnlockCompletionTimestamp(fakeClock.nowUtc())
|
||||
.build());
|
||||
|
||||
Optional<RegistryLock> mostRecent = getMostRecentUnlockedRegistryLockByRepoId(lock.getRepoId());
|
||||
assertThat(mostRecent.get().getRevisionId()).isEqualTo(lock.getRevisionId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoad_verifiedUnlock_empty() {
|
||||
RegistryLock completedLock =
|
||||
createLock().asBuilder().setLockCompletionTimestamp(fakeClock.nowUtc()).build();
|
||||
saveRegistryLock(completedLock);
|
||||
assertThat(getMostRecentUnlockedRegistryLockByRepoId(completedLock.getRepoId()).isPresent())
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
private RegistryLock createLock() {
|
||||
return new RegistryLock.Builder()
|
||||
.setRepoId("repoId")
|
||||
|
|
|
@ -40,9 +40,17 @@ public class SqlHelper {
|
|||
return jpaTm().transact(() -> RegistryLockDao.getMostRecentVerifiedLockByRepoId(repoId));
|
||||
}
|
||||
|
||||
public static Optional<RegistryLock> getMostRecentUnlockedRegistryLockByRepoId(String repoId) {
|
||||
return jpaTm().transact(() -> RegistryLockDao.getMostRecentVerifiedUnlockByRepoId(repoId));
|
||||
}
|
||||
|
||||
public static ImmutableList<RegistryLock> getRegistryLocksByRegistrarId(String registrarId) {
|
||||
return jpaTm().transact(() -> RegistryLockDao.getLocksByRegistrarId(registrarId));
|
||||
}
|
||||
|
||||
public static Optional<RegistryLock> getRegistryLockByRevisionId(long revisionId) {
|
||||
return jpaTm().transact(() -> RegistryLockDao.getByRevisionId(revisionId));
|
||||
}
|
||||
|
||||
private SqlHelper() {}
|
||||
}
|
||||
|
|
|
@ -23,6 +23,7 @@ import static google.registry.testing.DatastoreHelper.getOnlyHistoryEntryOfType;
|
|||
import static google.registry.testing.DatastoreHelper.newDomainBase;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.SqlHelper.getRegistryLockByRevisionId;
|
||||
import static google.registry.testing.SqlHelper.getRegistryLockByVerificationCode;
|
||||
import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STATUSES;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
@ -80,23 +81,26 @@ public final class DomainLockUtilsTest {
|
|||
|
||||
@Test
|
||||
public void testSuccess_createLock() {
|
||||
domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
RegistryLock lock =
|
||||
domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
assertNoDomainChanges();
|
||||
assertThat(lock.getLockCompletionTimestamp().isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_createUnlock() {
|
||||
domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
RegistryLock lock =
|
||||
domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false);
|
||||
domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false);
|
||||
domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false);
|
||||
assertThat(lock.getUnlockCompletionTimestamp().isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_createUnlock_adminUnlockingAdmin() {
|
||||
domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", null, true);
|
||||
RegistryLock lock =
|
||||
domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", null, true);
|
||||
domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), true);
|
||||
domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", true);
|
||||
domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", true);
|
||||
assertThat(lock.getUnlockCompletionTimestamp().isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
|
@ -130,9 +134,7 @@ public final class DomainLockUtilsTest {
|
|||
|
||||
@Test
|
||||
public void testSuccess_applyUnlockDomain() {
|
||||
RegistryLock lock =
|
||||
domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false);
|
||||
domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
RegistryLock unlock =
|
||||
domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false);
|
||||
domainLockUtils.verifyAndApplyUnlock(unlock.getVerificationCode(), false);
|
||||
|
@ -189,6 +191,31 @@ public final class DomainLockUtilsTest {
|
|||
verifyProperlyUnlockedDomain(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_regularLock_relockSet() {
|
||||
domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
RegistryLock oldLock =
|
||||
domainLockUtils.administrativelyApplyUnlock(DOMAIN_NAME, "TheRegistrar", false);
|
||||
RegistryLock newLock =
|
||||
domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
newLock = domainLockUtils.verifyAndApplyLock(newLock.getVerificationCode(), false);
|
||||
assertThat(
|
||||
getRegistryLockByRevisionId(oldLock.getRevisionId()).get().getRelock().getRevisionId())
|
||||
.isEqualTo(newLock.getRevisionId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_administrativelyLock_relockSet() {
|
||||
domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
RegistryLock oldLock =
|
||||
domainLockUtils.administrativelyApplyUnlock(DOMAIN_NAME, "TheRegistrar", false);
|
||||
RegistryLock newLock =
|
||||
domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
assertThat(
|
||||
getRegistryLockByRevisionId(oldLock.getRevisionId()).get().getRelock().getRevisionId())
|
||||
.isEqualTo(newLock.getRevisionId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_createUnlock_alreadyPendingUnlock() {
|
||||
RegistryLock lock =
|
||||
|
|
|
@ -31,6 +31,7 @@ PATH CLASS METHOD
|
|||
/_dr/task/rdeStaging RdeStagingAction GET,POST n INTERNAL,API APP ADMIN
|
||||
/_dr/task/rdeUpload RdeUploadAction POST n INTERNAL,API APP ADMIN
|
||||
/_dr/task/refreshDnsOnHostRename RefreshDnsOnHostRenameAction GET n INTERNAL,API APP ADMIN
|
||||
/_dr/task/relockDomain RelockDomainAction POST y INTERNAL,API APP ADMIN
|
||||
/_dr/task/resaveAllEppResources ResaveAllEppResourcesAction GET n INTERNAL,API APP ADMIN
|
||||
/_dr/task/resaveEntity ResaveEntityAction POST n INTERNAL,API APP ADMIN
|
||||
/_dr/task/syncGroupMembers SyncGroupMembersAction POST n INTERNAL,API APP ADMIN
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue