mirror of
https://github.com/google/nomulus.git
synced 2025-06-23 21:00:50 +02:00
Add RegistryLockVerifyAction (#461)
* Add RegistryLockVerifyAction The action takes two parameters - isLock is a boolean, determining whether we're trying to lock or unlock a domain - lockVerificationCode is the UUID by which we'll look up the lock object in question. The lock in question must not be expired and must be in a valid lockable / unlockable state * Some responses to CR * Add slash and move test method * Add more data and tests * Fix screenshot
This commit is contained in:
parent
7f86cab87a
commit
af8ef38b0a
13 changed files with 578 additions and 4 deletions
|
@ -61,6 +61,11 @@
|
|||
<url-pattern>/registry-lock-get</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<servlet-mapping>
|
||||
<servlet-name>frontend-servlet</servlet-name>
|
||||
<url-pattern>/registry-lock-verify</url-pattern>
|
||||
</servlet-mapping>
|
||||
|
||||
<!-- Security config -->
|
||||
<security-constraint>
|
||||
<web-resource-collection>
|
||||
|
|
|
@ -31,6 +31,7 @@ import google.registry.ui.server.registrar.OteStatusAction;
|
|||
import google.registry.ui.server.registrar.RegistrarConsoleModule;
|
||||
import google.registry.ui.server.registrar.RegistrarSettingsAction;
|
||||
import google.registry.ui.server.registrar.RegistryLockGetAction;
|
||||
import google.registry.ui.server.registrar.RegistryLockVerifyAction;
|
||||
|
||||
/** Dagger component with per-request lifetime for "default" App Engine module. */
|
||||
@RequestScope
|
||||
|
@ -53,6 +54,8 @@ interface FrontendRequestComponent {
|
|||
|
||||
RegistryLockGetAction registryLockGetAction();
|
||||
|
||||
RegistryLockVerifyAction registryLockVerifyAction();
|
||||
|
||||
@Subcomponent.Builder
|
||||
abstract class Builder implements RequestComponentBuilder<FrontendRequestComponent> {
|
||||
@Override public abstract Builder requestModule(RequestModule requestModule);
|
||||
|
|
|
@ -38,7 +38,7 @@ public abstract class LockOrUnlockDomainCommand extends ConfirmingCommand
|
|||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
static final ImmutableSet<StatusValue> REGISTRY_LOCK_STATUSES =
|
||||
public static final ImmutableSet<StatusValue> REGISTRY_LOCK_STATUSES =
|
||||
ImmutableSet.of(
|
||||
SERVER_DELETE_PROHIBITED, SERVER_TRANSFER_PROHIBITED, SERVER_UPDATE_PROHIBITED);
|
||||
|
||||
|
|
|
@ -14,7 +14,7 @@
|
|||
|
||||
package google.registry.ui.server.registrar;
|
||||
|
||||
|
||||
import static google.registry.request.RequestParameters.extractBooleanParameter;
|
||||
import static google.registry.request.RequestParameters.extractOptionalIntParameter;
|
||||
import static google.registry.request.RequestParameters.extractOptionalParameter;
|
||||
import static google.registry.request.RequestParameters.extractRequiredParameter;
|
||||
|
@ -144,4 +144,16 @@ public final class RegistrarConsoleModule {
|
|||
static Optional<String> provideOptionalPasscode(HttpServletRequest req) {
|
||||
return extractOptionalParameter(req, "passcode");
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter("lockVerificationCode")
|
||||
static String provideLockVerificationCode(HttpServletRequest req) {
|
||||
return extractRequiredParameter(req, "lockVerificationCode");
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter("isLock")
|
||||
static Boolean provideIsLock(HttpServletRequest req) {
|
||||
return extractBooleanParameter(req, "isLock");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -0,0 +1,97 @@
|
|||
// 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.ui.server.registrar;
|
||||
|
||||
import static google.registry.ui.server.SoyTemplateUtils.CSS_RENAMING_MAP_SUPPLIER;
|
||||
|
||||
import com.google.common.base.Supplier;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.template.soy.tofu.SoyTofu;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.schema.domain.RegistryLock;
|
||||
import google.registry.tools.DomainLockUtils;
|
||||
import google.registry.ui.server.SoyTemplateUtils;
|
||||
import google.registry.ui.soy.registrar.RegistryLockVerificationSoyInfo;
|
||||
import google.registry.util.Clock;
|
||||
import java.util.HashMap;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/** Action that allows for verification of registry lock / unlock requests */
|
||||
@Action(
|
||||
service = Action.Service.DEFAULT,
|
||||
path = RegistryLockVerifyAction.PATH,
|
||||
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||
public final class RegistryLockVerifyAction extends HtmlAction {
|
||||
|
||||
public static final String PATH = "/registry-lock-verify";
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private static final Supplier<SoyTofu> TOFU_SUPPLIER =
|
||||
SoyTemplateUtils.createTofuSupplier(
|
||||
google.registry.ui.soy.ConsoleSoyInfo.getInstance(),
|
||||
google.registry.ui.soy.AnalyticsSoyInfo.getInstance(),
|
||||
google.registry.ui.soy.registrar.RegistryLockVerificationSoyInfo.getInstance());
|
||||
|
||||
private final Clock clock;
|
||||
private final String lockVerificationCode;
|
||||
private final Boolean isLock;
|
||||
|
||||
@Inject
|
||||
public RegistryLockVerifyAction(
|
||||
Clock clock,
|
||||
@Parameter("lockVerificationCode") String lockVerificationCode,
|
||||
@Parameter("isLock") Boolean isLock) {
|
||||
this.clock = clock;
|
||||
this.lockVerificationCode = lockVerificationCode;
|
||||
this.isLock = isLock;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void runAfterLogin(HashMap<String, Object> data) {
|
||||
try {
|
||||
boolean isAdmin = authResult.userAuthInfo().get().isUserAdmin();
|
||||
final RegistryLock resultLock;
|
||||
if (isLock) {
|
||||
resultLock = DomainLockUtils.verifyAndApplyLock(lockVerificationCode, isAdmin, clock);
|
||||
} else {
|
||||
resultLock = DomainLockUtils.verifyAndApplyUnlock(lockVerificationCode, isAdmin, clock);
|
||||
}
|
||||
data.put("isLock", isLock);
|
||||
data.put("success", true);
|
||||
data.put("fullyQualifiedDomainName", resultLock.getDomainName());
|
||||
} catch (Throwable t) {
|
||||
logger.atWarning().withCause(t).log(
|
||||
"Error when verifying verification code %s", lockVerificationCode);
|
||||
data.put("success", false);
|
||||
data.put("errorMessage", Throwables.getRootCause(t).getMessage());
|
||||
}
|
||||
response.setPayload(
|
||||
TOFU_SUPPLIER
|
||||
.get()
|
||||
.newRenderer(RegistryLockVerificationSoyInfo.VERIFICATION_PAGE)
|
||||
.setCssRenamingMap(CSS_RENAMING_MAP_SUPPLIER.get())
|
||||
.setData(data)
|
||||
.render());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPath() {
|
||||
return PATH;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,71 @@
|
|||
// Copyright 2019 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.
|
||||
|
||||
{namespace registry.soy.registrar.registrylock.verification}
|
||||
|
||||
|
||||
/**
|
||||
* Results page for a registry lock/unlock verification.
|
||||
*/
|
||||
{template .verificationPage}
|
||||
{@param username: string} /** Arbitrary username to display. */
|
||||
{@param analyticsConfig: [googleAnalyticsId: string|null]}
|
||||
{@param success: bool}
|
||||
{@param? errorMessage: string}
|
||||
{@param? isLock: bool}
|
||||
{@param? fullyQualifiedDomainName: string}
|
||||
{call registry.soy.console.header}
|
||||
{param app: 'registrar' /}
|
||||
{param subtitle: 'Verify Registry Lock' /}
|
||||
{param analyticsConfig: $analyticsConfig /}
|
||||
{/call}
|
||||
{call registry.soy.console.googlebar data="all" /}
|
||||
<div id="reg-content-and-footer">
|
||||
<div id="reg-content">
|
||||
<h1>Registry Lock Verification</h1>
|
||||
{if $success}
|
||||
{call .success data="all" /}
|
||||
{else}
|
||||
{call .failure data="all" /}
|
||||
{/if}
|
||||
<h3><a href="/registrar">Return to Registrar Console</a></h3>
|
||||
</div>
|
||||
{call registry.soy.console.footer /}
|
||||
</div>
|
||||
{/template}
|
||||
|
||||
/**
|
||||
* Result page for failure, e.g. the UUID was invalid
|
||||
*/
|
||||
{template .failure}
|
||||
{@param? errorMessage: string}
|
||||
<h2 class="{css('kd-errormessage')}">Failed: {if isNonnull($errorMessage)}
|
||||
{$errorMessage}
|
||||
{else}
|
||||
Undefined error message
|
||||
{/if}
|
||||
</h2>
|
||||
{/template}
|
||||
|
||||
/**
|
||||
* Result page for a successful lock / unlock.
|
||||
*/
|
||||
{template .success}
|
||||
{@param? isLock: bool}
|
||||
{@param? fullyQualifiedDomainName: string}
|
||||
<h3>
|
||||
Success: {if $isLock}lock{else}unlock{/if} has been applied to {$fullyQualifiedDomainName}
|
||||
</h3>
|
||||
{/template}
|
||||
|
|
@ -30,6 +30,7 @@ import google.registry.tools.UpdateReservedListCommandTest;
|
|||
import google.registry.tools.server.CreatePremiumListActionTest;
|
||||
import google.registry.tools.server.UpdatePremiumListActionTest;
|
||||
import google.registry.ui.server.registrar.RegistryLockGetActionTest;
|
||||
import google.registry.ui.server.registrar.RegistryLockVerifyActionTest;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.ClassRule;
|
||||
|
@ -60,6 +61,7 @@ import org.junit.runners.Suite.SuiteClasses;
|
|||
PremiumListDaoTest.class,
|
||||
RegistryLockDaoTest.class,
|
||||
RegistryLockGetActionTest.class,
|
||||
RegistryLockVerifyActionTest.class,
|
||||
ReservedListDaoTest.class,
|
||||
UnlockDomainCommandTest.class,
|
||||
UpdatePremiumListActionTest.class,
|
||||
|
|
|
@ -83,7 +83,8 @@ public final class RegistryTestServer {
|
|||
route("/registrar-ote-setup", FrontendServlet.class),
|
||||
route("/registrar-ote-status", FrontendServlet.class),
|
||||
route("/registrar-settings", FrontendServlet.class),
|
||||
route("/registry-lock-get", FrontendServlet.class));
|
||||
route("/registry-lock-get", FrontendServlet.class),
|
||||
route("/registry-lock-verify", FrontendServlet.class));
|
||||
|
||||
private static final ImmutableList<Class<? extends Filter>> FILTERS = ImmutableList.of(
|
||||
ObjectifyFilter.class,
|
||||
|
|
|
@ -0,0 +1,345 @@
|
|||
// 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.ui.server.registrar;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.testing.DatastoreHelper.createTlds;
|
||||
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.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STATUSES;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import com.google.appengine.api.users.User;
|
||||
import com.google.appengine.api.users.UserService;
|
||||
import com.google.appengine.api.users.UserServiceFactory;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.model.billing.BillingEvent;
|
||||
import google.registry.model.billing.BillingEvent.Reason;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.model.registry.Registry;
|
||||
import google.registry.model.registry.RegistryLockDao;
|
||||
import google.registry.model.reporting.HistoryEntry;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageRule;
|
||||
import google.registry.request.auth.AuthLevel;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.UserAuthInfo;
|
||||
import google.registry.schema.domain.RegistryLock;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.DatastoreHelper;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.testing.InjectRule;
|
||||
import google.registry.testing.UserInfo;
|
||||
import java.util.UUID;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Before;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
import org.junit.runners.JUnit4;
|
||||
|
||||
@RunWith(JUnit4.class)
|
||||
public final class RegistryLockVerifyActionTest {
|
||||
|
||||
private final FakeClock fakeClock = new FakeClock();
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngineRule =
|
||||
AppEngineRule.builder()
|
||||
.withDatastore()
|
||||
.withUserService(UserInfo.create("marla.singer@example.com", "12345"))
|
||||
.build();
|
||||
|
||||
@Rule
|
||||
public final JpaIntegrationWithCoverageRule jpaRule =
|
||||
new JpaTestRules.Builder().withClock(fakeClock).buildIntegrationWithCoverageRule();
|
||||
|
||||
@Rule public final InjectRule inject = new InjectRule();
|
||||
|
||||
private final HttpServletRequest request = mock(HttpServletRequest.class);
|
||||
private final UserService userService = UserServiceFactory.getUserService();
|
||||
private final User user = new User("marla.singer@example.com", "gmail.com", "12345");
|
||||
private final String lockId = "f1be78a2-2d61-458c-80f0-9dd8f2f8625f";
|
||||
|
||||
private FakeResponse response;
|
||||
private DomainBase domain;
|
||||
private AuthResult authResult;
|
||||
private RegistryLockVerifyAction action;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
createTlds("tld", "net");
|
||||
HostResource host = persistActiveHost("ns1.example.net");
|
||||
domain = persistResource(newDomainBase("example.tld", host));
|
||||
when(request.getRequestURI()).thenReturn("https://registry.example/registry-lock-verification");
|
||||
action = createAction(lockId, true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_lockDomain() {
|
||||
RegistryLockDao.save(createLock());
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
assertThat(reloadDomain().getStatusValues()).containsExactlyElementsIn(REGISTRY_LOCK_STATUSES);
|
||||
assertThat(response.getPayload()).contains("Success: lock has been applied to example.tld");
|
||||
HistoryEntry historyEntry = getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_UPDATE);
|
||||
assertThat(historyEntry.getRequestedByRegistrar()).isTrue();
|
||||
assertThat(historyEntry.getBySuperuser()).isFalse();
|
||||
assertThat(historyEntry.getReason())
|
||||
.isEqualTo("Lock or unlock of a domain through a RegistryLock operation");
|
||||
assertBillingEvent(historyEntry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_unlockDomain() {
|
||||
action = createAction(lockId, false);
|
||||
domain = persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
|
||||
RegistryLockDao.save(
|
||||
createLock().asBuilder().setUnlockRequestTimestamp(fakeClock.nowUtc()).build());
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
assertThat(response.getPayload()).contains("Success: unlock has been applied to example.tld");
|
||||
assertThat(reloadDomain().getStatusValues()).containsNoneIn(REGISTRY_LOCK_STATUSES);
|
||||
HistoryEntry historyEntry = getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_UPDATE);
|
||||
assertThat(historyEntry.getRequestedByRegistrar()).isTrue();
|
||||
assertThat(historyEntry.getBySuperuser()).isFalse();
|
||||
assertThat(historyEntry.getReason())
|
||||
.isEqualTo("Lock or unlock of a domain through a RegistryLock operation");
|
||||
assertBillingEvent(historyEntry);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_adminLock_createsOnlyHistoryEntry() {
|
||||
action.authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, true));
|
||||
RegistryLockDao.save(createLock().asBuilder().isSuperuser(true).build());
|
||||
|
||||
action.run();
|
||||
HistoryEntry historyEntry = getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_UPDATE);
|
||||
assertThat(historyEntry.getRequestedByRegistrar()).isFalse();
|
||||
assertThat(historyEntry.getBySuperuser()).isTrue();
|
||||
DatastoreHelper.assertNoBillingEvents();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_badVerificationCode() {
|
||||
RegistryLockDao.save(
|
||||
createLock().asBuilder().setVerificationCode(UUID.randomUUID().toString()).build());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Invalid verification code");
|
||||
assertNoDomainChanges();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_alreadyVerified() {
|
||||
RegistryLockDao.save(
|
||||
createLock().asBuilder().setLockCompletionTimestamp(fakeClock.nowUtc()).build());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Domain example.tld is already locked");
|
||||
assertNoDomainChanges();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_expired() {
|
||||
RegistryLockDao.save(createLock());
|
||||
fakeClock.advanceBy(Duration.standardHours(2));
|
||||
action.run();
|
||||
assertThat(response.getPayload())
|
||||
.contains("Failed: The pending lock has expired; please try again");
|
||||
assertNoDomainChanges();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_nonAdmin_verifyingAdminLock() {
|
||||
RegistryLockDao.save(createLock().asBuilder().isSuperuser(true).build());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Non-admin user cannot complete admin lock");
|
||||
assertNoDomainChanges();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_alreadyUnlocked() {
|
||||
action = createAction(lockId, false);
|
||||
RegistryLockDao.save(
|
||||
createLock()
|
||||
.asBuilder()
|
||||
.setLockCompletionTimestamp(fakeClock.nowUtc())
|
||||
.setUnlockRequestTimestamp(fakeClock.nowUtc())
|
||||
.setUnlockCompletionTimestamp(fakeClock.nowUtc())
|
||||
.build());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Domain example.tld is already unlocked");
|
||||
assertNoDomainChanges();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_alreadyLocked() {
|
||||
RegistryLockDao.save(createLock());
|
||||
domain = persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Domain example.tld is already locked");
|
||||
assertNoDomainChanges();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_notLoggedIn() {
|
||||
action.authResult = AuthResult.NOT_AUTHENTICATED;
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_MOVED_TEMPORARILY);
|
||||
assertThat(response.getHeaders()).containsKey("Location");
|
||||
assertNoDomainChanges();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_doesNotChangeLockObject() {
|
||||
// A failure when performing Datastore actions means that no actions should be taken in the
|
||||
// Cloud SQL RegistryLock object
|
||||
RegistryLock lock = createLock();
|
||||
RegistryLockDao.save(lock);
|
||||
// reload the lock to pick up creation time
|
||||
lock = RegistryLockDao.getByVerificationCode(lock.getVerificationCode()).get();
|
||||
fakeClock.advanceOneMilli();
|
||||
domain = persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
|
||||
action.run();
|
||||
// we would have failed during the Datastore segment of the action
|
||||
assertThat(response.getPayload()).contains("Failed: Domain example.tld is already locked");
|
||||
|
||||
// verify that the changes to the SQL object were rolled back
|
||||
RegistryLock afterAction =
|
||||
RegistryLockDao.getByVerificationCode(lock.getVerificationCode()).get();
|
||||
assertThat(afterAction).isEqualTo(lock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_isLockTrue_shouldBeFalse() {
|
||||
domain = persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
|
||||
RegistryLockDao.save(
|
||||
createLock()
|
||||
.asBuilder()
|
||||
.setLockCompletionTimestamp(fakeClock.nowUtc())
|
||||
.setUnlockRequestTimestamp(fakeClock.nowUtc())
|
||||
.build());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Domain example.tld is already locked");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_isLockFalse_shouldBeTrue() {
|
||||
action = createAction(lockId, false);
|
||||
RegistryLockDao.save(createLock());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Domain example.tld is already unlocked");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_lock_unlock_lockAgain() {
|
||||
RegistryLock lock = RegistryLockDao.save(createLock());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Success: lock has been applied to example.tld");
|
||||
String unlockVerificationCode = "some-unlock-code";
|
||||
RegistryLockDao.save(
|
||||
lock.asBuilder()
|
||||
.setVerificationCode(unlockVerificationCode)
|
||||
.setUnlockRequestTimestamp(fakeClock.nowUtc())
|
||||
.build());
|
||||
action = createAction(unlockVerificationCode, false);
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Success: unlock has been applied to example.tld");
|
||||
action = createAction(lockId, true);
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Invalid verification code");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_lock_lockAgain() {
|
||||
RegistryLockDao.save(createLock());
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Success: lock has been applied to example.tld");
|
||||
action = createAction(lockId, true);
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Domain example.tld is already locked");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unlock_unlockAgain() {
|
||||
action = createAction(lockId, false);
|
||||
domain = persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
|
||||
RegistryLockDao.save(
|
||||
createLock().asBuilder().setUnlockRequestTimestamp(fakeClock.nowUtc()).build());
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_OK);
|
||||
assertThat(response.getPayload()).contains("Success: unlock has been applied to example.tld");
|
||||
action = createAction(lockId, false);
|
||||
action.run();
|
||||
assertThat(response.getPayload()).contains("Failed: Domain example.tld is already unlocked");
|
||||
}
|
||||
|
||||
private RegistryLock createLock() {
|
||||
return new RegistryLock.Builder()
|
||||
.setDomainName("example.tld")
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setRepoId("repoId")
|
||||
.setRegistrarPocId("marla.singer@example.com")
|
||||
.isSuperuser(false)
|
||||
.setVerificationCode(lockId)
|
||||
.build();
|
||||
}
|
||||
|
||||
private DomainBase reloadDomain() {
|
||||
return ofy().load().entity(domain).now();
|
||||
}
|
||||
|
||||
private void assertNoDomainChanges() {
|
||||
assertThat(reloadDomain()).isEqualTo(domain);
|
||||
}
|
||||
|
||||
private void assertBillingEvent(HistoryEntry historyEntry) {
|
||||
DatastoreHelper.assertBillingEvents(
|
||||
new BillingEvent.OneTime.Builder()
|
||||
.setReason(Reason.SERVER_STATUS)
|
||||
.setTargetId(domain.getForeignKey())
|
||||
.setClientId(domain.getCurrentSponsorClientId())
|
||||
.setCost(Registry.get(domain.getTld()).getServerStatusChangeCost())
|
||||
.setEventTime(fakeClock.nowUtc())
|
||||
.setBillingTime(fakeClock.nowUtc())
|
||||
.setParent(historyEntry)
|
||||
.build());
|
||||
}
|
||||
|
||||
private RegistryLockVerifyAction createAction(String lockVerificationCode, Boolean isLock) {
|
||||
response = new FakeResponse();
|
||||
RegistryLockVerifyAction action =
|
||||
new RegistryLockVerifyAction(fakeClock, lockVerificationCode, isLock);
|
||||
authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
|
||||
action.req = request;
|
||||
action.response = response;
|
||||
action.authResult = authResult;
|
||||
action.userService = userService;
|
||||
action.logoFilename = "logo.png";
|
||||
action.productName = "Nomulus";
|
||||
action.analyticsConfig = ImmutableMap.of("googleAnalyticsId", "sampleId");
|
||||
action.xsrfTokenManager = new XsrfTokenManager(new FakeClock(), action.userService);
|
||||
return action;
|
||||
}
|
||||
}
|
|
@ -18,7 +18,9 @@ import static google.registry.server.Fixture.BASIC;
|
|||
import static google.registry.server.Route.route;
|
||||
import static google.registry.testing.AppEngineRule.makeRegistrar2;
|
||||
import static google.registry.testing.AppEngineRule.makeRegistrarContact2;
|
||||
import static google.registry.testing.DatastoreHelper.createTld;
|
||||
import static google.registry.testing.DatastoreHelper.loadRegistrar;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainBase;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||
|
||||
|
@ -26,7 +28,9 @@ import com.google.common.collect.ImmutableMap;
|
|||
import com.googlecode.objectify.ObjectifyFilter;
|
||||
import google.registry.model.ofy.OfyFilter;
|
||||
import google.registry.model.registrar.Registrar.State;
|
||||
import google.registry.model.registry.RegistryLockDao;
|
||||
import google.registry.module.frontend.FrontendServlet;
|
||||
import google.registry.schema.domain.RegistryLock;
|
||||
import google.registry.server.RegistryTestServer;
|
||||
import google.registry.testing.CertificateSamples;
|
||||
import org.junit.Rule;
|
||||
|
@ -46,7 +50,8 @@ public class RegistrarConsoleScreenshotTest extends WebDriverTestCase {
|
|||
.setRoutes(
|
||||
route("/registrar", FrontendServlet.class),
|
||||
route("/registrar-ote-status", FrontendServlet.class),
|
||||
route("/registrar-settings", FrontendServlet.class))
|
||||
route("/registrar-settings", FrontendServlet.class),
|
||||
route("/registry-lock-verify", FrontendServlet.class))
|
||||
.setFilters(ObjectifyFilter.class, OfyFilter.class)
|
||||
.setFixtures(BASIC)
|
||||
.setEmail("Marla.Singer@google.com")
|
||||
|
@ -370,4 +375,36 @@ public class RegistrarConsoleScreenshotTest extends WebDriverTestCase {
|
|||
Thread.sleep(500);
|
||||
driver.diffPage("page");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registryLockVerify_success() throws Throwable {
|
||||
String lockVerificationCode = "f1be78a2-2d61-458c-80f0-9dd8f2f8625f";
|
||||
server.runInAppEngineEnvironment(
|
||||
() -> {
|
||||
createTld("tld");
|
||||
persistResource(newDomainBase("example.tld"));
|
||||
RegistryLockDao.save(
|
||||
new RegistryLock.Builder()
|
||||
.setRegistrarPocId("johndoe@theregistrar.com")
|
||||
.setRepoId("repoId")
|
||||
.setRegistrarId("TheRegistrar")
|
||||
.setVerificationCode("f1be78a2-2d61-458c-80f0-9dd8f2f8625f")
|
||||
.isSuperuser(false)
|
||||
.setDomainName("example.tld")
|
||||
.build());
|
||||
return null;
|
||||
});
|
||||
driver.get(
|
||||
server.getUrl(
|
||||
"/registry-lock-verify?isLock=true&lockVerificationCode=" + lockVerificationCode));
|
||||
driver.waitForElement(By.id("reg-content"));
|
||||
driver.diffPage("page");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registryLockVerify_unknownLock() throws Throwable {
|
||||
driver.get(server.getUrl("/registry-lock-verify?isLock=true&lockVerificationCode=asdfasdf"));
|
||||
driver.waitForElement(By.id("reg-content"));
|
||||
driver.diffPage("page");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -6,3 +6,4 @@ PATH CLASS METHODS OK AUTH_METHODS
|
|||
/registrar-ote-status OteStatusAction POST n API,LEGACY USER PUBLIC
|
||||
/registrar-settings RegistrarSettingsAction POST n API,LEGACY USER PUBLIC
|
||||
/registry-lock-get RegistryLockGetAction GET n API,LEGACY USER PUBLIC
|
||||
/registry-lock-verify RegistryLockVerifyAction GET n API,LEGACY USER PUBLIC
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
Binary file not shown.
After Width: | Height: | Size: 29 KiB |
Loading…
Add table
Add a link
Reference in a new issue