diff --git a/core/src/main/java/google/registry/request/auth/OidcTokenAuthenticationMechanism.java b/core/src/main/java/google/registry/request/auth/OidcTokenAuthenticationMechanism.java index 4c7d75a9e..c206f1fdd 100644 --- a/core/src/main/java/google/registry/request/auth/OidcTokenAuthenticationMechanism.java +++ b/core/src/main/java/google/registry/request/auth/OidcTokenAuthenticationMechanism.java @@ -36,9 +36,9 @@ import javax.annotation.Nullable; import javax.inject.Inject; /** - * An authenticam mechanism that verifies the OIDC token. + * An authentication mechanism that verifies the OIDC token. * - *

Currently, two flavors are supported: one that checkes for the OIDC token as a regular bearer + *

Currently, two flavors are supported: one that checks for the OIDC token as a regular bearer * token, and another that checks for the OIDC token passed by IAP. In both cases, the {@link * AuthResult} with the highest {@link AuthLevel} possible is returned. So, if the email address for * which the token is minted exists both as a {@link User} and as a service account, the returned diff --git a/core/src/main/java/google/registry/tools/CreateOrUpdateUserCommand.java b/core/src/main/java/google/registry/tools/CreateOrUpdateUserCommand.java index 62b55e114..61ae060e9 100644 --- a/core/src/main/java/google/registry/tools/CreateOrUpdateUserCommand.java +++ b/core/src/main/java/google/registry/tools/CreateOrUpdateUserCommand.java @@ -14,6 +14,7 @@ package google.registry.tools; +import static com.google.common.base.Preconditions.checkArgument; import static google.registry.persistence.transaction.TransactionManagerFactory.tm; import static google.registry.util.PreconditionsUtils.checkArgumentNotNull; @@ -41,6 +42,15 @@ public abstract class CreateOrUpdateUserCommand extends ConfirmingCommand { + " to remove the field.") private String registryLockEmailAddress; + @Nullable + @Parameter( + names = "--registry_lock_password", + description = + "Sets the registry lock password for this user, or removes it (allowing the user to" + + " re-set it). Do not set the password explicitly unless in exceptional" + + " circumstances.") + private String registryLockPassword; + @Nullable @Parameter( names = "--admin", @@ -94,6 +104,25 @@ public abstract class CreateOrUpdateUserCommand extends ConfirmingCommand { builder.setRegistryLockEmailAddress(registryLockEmailAddress); } } + // Ditto the registry lock password + if (registryLockPassword != null) { + if (registryLockEmailAddress != null) { + // Edge case, make sure we're not removing an email and setting a password at the same time + checkArgument( + !registryLockEmailAddress.isEmpty(), + "Cannot set/remove registry lock password on a user without a registry lock email" + + " address"); + } else { + checkArgument( + user != null && user.getRegistryLockEmailAddress().isPresent(), + "Cannot set/remove registry lock password on a user without a registry lock email" + + " address"); + } + builder.removeRegistryLockPassword(); + if (!registryLockPassword.isEmpty()) { + builder.setRegistryLockPassword(registryLockPassword); + } + } tm().put(builder.build()); } } diff --git a/core/src/test/java/google/registry/tools/CreateUserCommandTest.java b/core/src/test/java/google/registry/tools/CreateUserCommandTest.java index e365067e6..c281e3909 100644 --- a/core/src/test/java/google/registry/tools/CreateUserCommandTest.java +++ b/core/src/test/java/google/registry/tools/CreateUserCommandTest.java @@ -91,10 +91,16 @@ public class CreateUserCommandTest extends CommandTestCase { runCommandForced( "--email", "user@example.test", + "--registrar_roles", + "TheRegistrar=PRIMARY_CONTACT", "--registry_lock_email_address", - "registrylockemail@otherexample.test"); - assertThat(loadExistingUser("user@example.test").getRegistryLockEmailAddress()) - .hasValue("registrylockemail@otherexample.test"); + "registrylockemail@otherexample.test", + "--registry_lock_password", + "password"); + User user = loadExistingUser("user@example.test"); + assertThat(user.getRegistryLockEmailAddress()).hasValue("registrylockemail@otherexample.test"); + assertThat(user.verifyRegistryLockPassword("password")).isTrue(); + assertThat(user.verifyRegistryLockPassword("foobar")).isFalse(); } @Test @@ -174,4 +180,18 @@ public class CreateUserCommandTest extends CommandTestCase { .hasMessageThat() .isEqualTo("Provided email this is not valid is not a valid email address"); } + + @Test + void testFailure_registryLockPassword_withoutEmail() { + assertThat( + assertThrows( + IllegalArgumentException.class, + () -> + runCommandForced( + "--email", "user@example.test", "--registry_lock_password", "password"))) + .hasMessageThat() + .isEqualTo( + "Cannot set/remove registry lock password on a user without a registry lock email" + + " address"); + } } diff --git a/core/src/test/java/google/registry/tools/UpdateUserCommandTest.java b/core/src/test/java/google/registry/tools/UpdateUserCommandTest.java index f3135eaed..502f130cd 100644 --- a/core/src/test/java/google/registry/tools/UpdateUserCommandTest.java +++ b/core/src/test/java/google/registry/tools/UpdateUserCommandTest.java @@ -16,6 +16,7 @@ package google.registry.tools; import static com.google.common.truth.Truth.assertThat; import static google.registry.testing.DatabaseHelper.loadExistingUser; +import static google.registry.testing.DatabaseHelper.persistResource; import static google.registry.testing.DatabaseHelper.putInDb; import static org.junit.Assert.assertThrows; @@ -98,6 +99,44 @@ public class UpdateUserCommandTest extends CommandTestCase { .isEqualTo(GlobalRole.FTE); } + @Test + void testSuccess_removePassword() throws Exception { + // Empty password value removes the password + persistResource( + loadExistingUser("user@example.test") + .asBuilder() + .setUserRoles( + new UserRoles.Builder() + .setRegistrarRoles(ImmutableMap.of("TheRegistrar", RegistrarRole.TECH_CONTACT)) + .build()) + .setRegistryLockEmailAddress("registrylock@example.test") + .setRegistryLockPassword("password") + .build()); + assertThat(loadExistingUser("user@example.test").hasRegistryLockPassword()).isTrue(); + runCommandForced("--email", "user@example.test", "--registry_lock_password", ""); + assertThat(loadExistingUser("user@example.test").hasRegistryLockPassword()).isFalse(); + } + + @Test + void testSuccess_setsPassword() throws Exception { + persistResource( + loadExistingUser("user@example.test") + .asBuilder() + .setUserRoles( + new UserRoles.Builder() + .setRegistrarRoles(ImmutableMap.of("TheRegistrar", RegistrarRole.TECH_CONTACT)) + .build()) + .setRegistryLockEmailAddress("registrylock@example.test") + .setRegistryLockPassword("password") + .build()); + assertThat(loadExistingUser("user@example.test").verifyRegistryLockPassword("password")) + .isTrue(); + runCommandForced("--email", "user@example.test", "--registry_lock_password", "foobar"); + assertThat(loadExistingUser("user@example.test").verifyRegistryLockPassword("password")) + .isFalse(); + assertThat(loadExistingUser("user@example.test").verifyRegistryLockPassword("foobar")).isTrue(); + } + @Test void testFailure_doesntExist() { assertThat( @@ -122,4 +161,18 @@ public class UpdateUserCommandTest extends CommandTestCase { .hasMessageThat() .isEqualTo("Provided email this is not valid is not a valid email address"); } + + @Test + void testFailure_setPassword_noEmail() { + assertThat( + assertThrows( + IllegalArgumentException.class, + () -> + runCommandForced( + "--email", "user@example.test", "--registry_lock_password", "foobar"))) + .hasMessageThat() + .isEqualTo( + "Cannot set/remove registry lock password on a user without a registry lock email" + + " address"); + } }