mirror of
https://github.com/google/nomulus.git
synced 2025-04-30 03:57:51 +02:00
Create a registry lock permission and corresponding account manager role (#1740)
* Create a registry lock permission and corresponding account manager role This allows us to distinguish between standard account managers and users that might have the registry lock permission. This will make the registry lock password-setting flow easier (user can reset their password iff they have the REGISTRY_LOCK permission, instead of having a separate boolean) and allows us to easily determine whether or not a user should have access to registry lock views in the UI.
This commit is contained in:
parent
2f9a45c91f
commit
6d66f52359
6 changed files with 90 additions and 31 deletions
|
@ -63,5 +63,7 @@ public enum ConsolePermission {
|
||||||
/** View announcements in the UI. */
|
/** View announcements in the UI. */
|
||||||
VIEW_ANNOUNCEMENTS,
|
VIEW_ANNOUNCEMENTS,
|
||||||
/** Viewing a record of actions performed in the UI for a particular registrar. */
|
/** Viewing a record of actions performed in the UI for a particular registrar. */
|
||||||
VIEW_ACTIVITY_LOG
|
VIEW_ACTIVITY_LOG,
|
||||||
|
/** View and perform registry locks. */
|
||||||
|
REGISTRY_LOCK
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,8 @@ public class ConsoleRoleDefinitions {
|
||||||
ConsolePermission.VIEW_OPERATIONAL_DATA,
|
ConsolePermission.VIEW_OPERATIONAL_DATA,
|
||||||
ConsolePermission.SEND_ANNOUNCEMENTS,
|
ConsolePermission.SEND_ANNOUNCEMENTS,
|
||||||
ConsolePermission.VIEW_ANNOUNCEMENTS,
|
ConsolePermission.VIEW_ANNOUNCEMENTS,
|
||||||
ConsolePermission.VIEW_ACTIVITY_LOG);
|
ConsolePermission.VIEW_ACTIVITY_LOG,
|
||||||
|
ConsolePermission.REGISTRY_LOCK);
|
||||||
|
|
||||||
/** Permissions for a registry support lead. */
|
/** Permissions for a registry support lead. */
|
||||||
static final ImmutableSet<ConsolePermission> SUPPORT_LEAD_PERMISSIONS =
|
static final ImmutableSet<ConsolePermission> SUPPORT_LEAD_PERMISSIONS =
|
||||||
|
@ -76,10 +77,17 @@ public class ConsoleRoleDefinitions {
|
||||||
ConsolePermission.VIEW_OPERATIONAL_DATA,
|
ConsolePermission.VIEW_OPERATIONAL_DATA,
|
||||||
ConsolePermission.VIEW_ANNOUNCEMENTS);
|
ConsolePermission.VIEW_ANNOUNCEMENTS);
|
||||||
|
|
||||||
|
/** Permissions for a registrar partner account manager that can perform registry locks. */
|
||||||
|
static final ImmutableSet<ConsolePermission> ACCOUNT_MANAGER_WITH_REGISTRY_LOCK_PERMISSIONS =
|
||||||
|
new ImmutableSet.Builder<ConsolePermission>()
|
||||||
|
.addAll(ACCOUNT_MANAGER_PERMISSIONS)
|
||||||
|
.add(ConsolePermission.REGISTRY_LOCK)
|
||||||
|
.build();
|
||||||
|
|
||||||
/** Permissions for the tech contact of a registrar. */
|
/** Permissions for the tech contact of a registrar. */
|
||||||
static final ImmutableSet<ConsolePermission> TECH_CONTACT_PERMISSIONS =
|
static final ImmutableSet<ConsolePermission> TECH_CONTACT_PERMISSIONS =
|
||||||
new ImmutableSet.Builder<ConsolePermission>()
|
new ImmutableSet.Builder<ConsolePermission>()
|
||||||
.addAll(ACCOUNT_MANAGER_PERMISSIONS)
|
.addAll(ACCOUNT_MANAGER_WITH_REGISTRY_LOCK_PERMISSIONS)
|
||||||
.add(
|
.add(
|
||||||
ConsolePermission.MANAGE_ACCREDITATION,
|
ConsolePermission.MANAGE_ACCREDITATION,
|
||||||
ConsolePermission.CONFIGURE_EPP_CONNECTION,
|
ConsolePermission.CONFIGURE_EPP_CONNECTION,
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
package google.registry.model.console;
|
package google.registry.model.console;
|
||||||
|
|
||||||
import static google.registry.model.console.ConsoleRoleDefinitions.ACCOUNT_MANAGER_PERMISSIONS;
|
import static google.registry.model.console.ConsoleRoleDefinitions.ACCOUNT_MANAGER_PERMISSIONS;
|
||||||
|
import static google.registry.model.console.ConsoleRoleDefinitions.ACCOUNT_MANAGER_WITH_REGISTRY_LOCK_PERMISSIONS;
|
||||||
import static google.registry.model.console.ConsoleRoleDefinitions.PRIMARY_CONTACT_PERMISSIONS;
|
import static google.registry.model.console.ConsoleRoleDefinitions.PRIMARY_CONTACT_PERMISSIONS;
|
||||||
import static google.registry.model.console.ConsoleRoleDefinitions.TECH_CONTACT_PERMISSIONS;
|
import static google.registry.model.console.ConsoleRoleDefinitions.TECH_CONTACT_PERMISSIONS;
|
||||||
|
|
||||||
|
@ -25,6 +26,8 @@ public enum RegistrarRole {
|
||||||
|
|
||||||
/** The user is a standard account manager at a registrar. */
|
/** The user is a standard account manager at a registrar. */
|
||||||
ACCOUNT_MANAGER(ACCOUNT_MANAGER_PERMISSIONS),
|
ACCOUNT_MANAGER(ACCOUNT_MANAGER_PERMISSIONS),
|
||||||
|
/** The user is an account manager that can perform registry locks. */
|
||||||
|
ACCOUNT_MANAGER_WITH_REGISTRY_LOCK(ACCOUNT_MANAGER_WITH_REGISTRY_LOCK_PERMISSIONS),
|
||||||
/** The user is a technical contact of a registrar. */
|
/** The user is a technical contact of a registrar. */
|
||||||
TECH_CONTACT(TECH_CONTACT_PERMISSIONS),
|
TECH_CONTACT(TECH_CONTACT_PERMISSIONS),
|
||||||
/** The user is the primary contact at a registrar. */
|
/** The user is the primary contact at a registrar. */
|
||||||
|
|
|
@ -40,12 +40,6 @@ public class User extends ImmutableObject implements Buildable {
|
||||||
/** Roles (which grant permissions) associated with this user. */
|
/** Roles (which grant permissions) associated with this user. */
|
||||||
private UserRoles userRoles;
|
private UserRoles userRoles;
|
||||||
|
|
||||||
/**
|
|
||||||
* Whether the contact is allowed to set their registry lock password through the registrar
|
|
||||||
* console. This will be set to false on contact creation and when the user sets a password.
|
|
||||||
*/
|
|
||||||
boolean allowedToSetRegistryLockPassword = false;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A hashed password that exists iff this contact is registry-lock-enabled. The hash is a base64
|
* A hashed password that exists iff this contact is registry-lock-enabled. The hash is a base64
|
||||||
* encoded SHA256 string.
|
* encoded SHA256 string.
|
||||||
|
@ -55,6 +49,10 @@ public class User extends ImmutableObject implements Buildable {
|
||||||
/** Randomly generated hash salt. */
|
/** Randomly generated hash salt. */
|
||||||
String registryLockPasswordSalt;
|
String registryLockPasswordSalt;
|
||||||
|
|
||||||
|
public long getId() {
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
public String getGaiaId() {
|
public String getGaiaId() {
|
||||||
return gaiaId;
|
return gaiaId;
|
||||||
}
|
}
|
||||||
|
@ -67,11 +65,7 @@ public class User extends ImmutableObject implements Buildable {
|
||||||
return userRoles;
|
return userRoles;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAllowedToSetRegistryLockPassword() {
|
public boolean hasRegistryLockPassword() {
|
||||||
return allowedToSetRegistryLockPassword;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean isRegistryLockAllowed() {
|
|
||||||
return !isNullOrEmpty(registryLockPasswordHash) && !isNullOrEmpty(registryLockPasswordSalt);
|
return !isNullOrEmpty(registryLockPasswordHash) && !isNullOrEmpty(registryLockPasswordSalt);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -85,6 +79,22 @@ public class User extends ImmutableObject implements Buildable {
|
||||||
.equals(registryLockPasswordHash);
|
.equals(registryLockPasswordHash);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the user has the registry lock permission on any registrar or globally.
|
||||||
|
*
|
||||||
|
* <p>If so, they should be allowed to (re)set their registry lock password.
|
||||||
|
*/
|
||||||
|
public boolean hasAnyRegistryLockPermission() {
|
||||||
|
if (userRoles == null) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (userRoles.isAdmin() || userRoles.hasGlobalPermission(ConsolePermission.REGISTRY_LOCK)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return userRoles.getRegistrarRoles().values().stream()
|
||||||
|
.anyMatch(role -> role.hasPermission(ConsolePermission.REGISTRY_LOCK));
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public Builder asBuilder() {
|
public Builder asBuilder() {
|
||||||
return new Builder(clone(this));
|
return new Builder(clone(this));
|
||||||
|
@ -99,6 +109,7 @@ public class User extends ImmutableObject implements Buildable {
|
||||||
super(user);
|
super(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
public User build() {
|
public User build() {
|
||||||
checkArgumentNotNull(getInstance().gaiaId, "Gaia ID cannot be null");
|
checkArgumentNotNull(getInstance().gaiaId, "Gaia ID cannot be null");
|
||||||
checkArgumentNotNull(getInstance().emailAddress, "Email address cannot be null");
|
checkArgumentNotNull(getInstance().emailAddress, "Email address cannot be null");
|
||||||
|
@ -123,25 +134,22 @@ public class User extends ImmutableObject implements Buildable {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setAllowedToSetRegistryLockPassword(boolean allowedToSetRegistryLockPassword) {
|
public Builder removeRegistryLockPassword() {
|
||||||
if (allowedToSetRegistryLockPassword) {
|
getInstance().registryLockPasswordHash = null;
|
||||||
getInstance().registryLockPasswordSalt = null;
|
getInstance().registryLockPasswordSalt = null;
|
||||||
getInstance().registryLockPasswordHash = null;
|
|
||||||
}
|
|
||||||
getInstance().allowedToSetRegistryLockPassword = allowedToSetRegistryLockPassword;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Builder setRegistryLockPassword(String registryLockPassword) {
|
public Builder setRegistryLockPassword(String registryLockPassword) {
|
||||||
checkArgument(
|
checkArgument(
|
||||||
getInstance().allowedToSetRegistryLockPassword,
|
getInstance().hasAnyRegistryLockPermission(), "User has no registry lock permission");
|
||||||
"Not allowed to set registry lock password for this user");
|
checkArgument(
|
||||||
|
!getInstance().hasRegistryLockPassword(), "User already has a password, remove it first");
|
||||||
checkArgument(
|
checkArgument(
|
||||||
!isNullOrEmpty(registryLockPassword), "Registry lock password was null or empty");
|
!isNullOrEmpty(registryLockPassword), "Registry lock password was null or empty");
|
||||||
getInstance().registryLockPasswordSalt = base64().encode(SALT_SUPPLIER.get());
|
getInstance().registryLockPasswordSalt = base64().encode(SALT_SUPPLIER.get());
|
||||||
getInstance().registryLockPasswordHash =
|
getInstance().registryLockPasswordHash =
|
||||||
hashPassword(registryLockPassword, getInstance().registryLockPasswordSalt);
|
hashPassword(registryLockPassword, getInstance().registryLockPasswordSalt);
|
||||||
getInstance().allowedToSetRegistryLockPassword = false;
|
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,21 +49,30 @@ public class ConsoleRoleDefinitionsTest {
|
||||||
// Note: we can't use Truth's IterableSubject to check all the subset/superset restrictions
|
// Note: we can't use Truth's IterableSubject to check all the subset/superset restrictions
|
||||||
// because it is generic to iterables and doesn't know about sets.
|
// because it is generic to iterables and doesn't know about sets.
|
||||||
assertThat(
|
assertThat(
|
||||||
ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS.containsAll(
|
ConsoleRoleDefinitions.ACCOUNT_MANAGER_WITH_REGISTRY_LOCK_PERMISSIONS.containsAll(
|
||||||
ConsoleRoleDefinitions.SUPPORT_AGENT_PERMISSIONS))
|
ConsoleRoleDefinitions.ACCOUNT_MANAGER_PERMISSIONS))
|
||||||
.isTrue();
|
.isTrue();
|
||||||
assertThat(
|
assertThat(
|
||||||
ConsoleRoleDefinitions.SUPPORT_AGENT_PERMISSIONS.containsAll(
|
ConsoleRoleDefinitions.ACCOUNT_MANAGER_PERMISSIONS.containsAll(
|
||||||
ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS))
|
ConsoleRoleDefinitions.ACCOUNT_MANAGER_WITH_REGISTRY_LOCK_PERMISSIONS))
|
||||||
.isFalse();
|
.isFalse();
|
||||||
|
|
||||||
assertThat(
|
assertThat(
|
||||||
ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS.containsAll(
|
ConsoleRoleDefinitions.TECH_CONTACT_PERMISSIONS.containsAll(
|
||||||
ConsoleRoleDefinitions.SUPPORT_AGENT_PERMISSIONS))
|
ConsoleRoleDefinitions.ACCOUNT_MANAGER_WITH_REGISTRY_LOCK_PERMISSIONS))
|
||||||
.isTrue();
|
.isTrue();
|
||||||
assertThat(
|
assertThat(
|
||||||
ConsoleRoleDefinitions.SUPPORT_AGENT_PERMISSIONS.containsAll(
|
ConsoleRoleDefinitions.ACCOUNT_MANAGER_WITH_REGISTRY_LOCK_PERMISSIONS.containsAll(
|
||||||
ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS))
|
ConsoleRoleDefinitions.TECH_CONTACT_PERMISSIONS))
|
||||||
|
.isFalse();
|
||||||
|
|
||||||
|
assertThat(
|
||||||
|
ConsoleRoleDefinitions.PRIMARY_CONTACT_PERMISSIONS.containsAll(
|
||||||
|
ConsoleRoleDefinitions.TECH_CONTACT_PERMISSIONS))
|
||||||
|
.isTrue();
|
||||||
|
assertThat(
|
||||||
|
ConsoleRoleDefinitions.TECH_CONTACT_PERMISSIONS.containsAll(
|
||||||
|
ConsoleRoleDefinitions.PRIMARY_CONTACT_PERMISSIONS))
|
||||||
.isFalse();
|
.isFalse();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -58,4 +58,33 @@ public class UserTest {
|
||||||
builder.setUserRoles(new UserRoles.Builder().build());
|
builder.setUserRoles(new UserRoles.Builder().build());
|
||||||
builder.build();
|
builder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testRegistryLockPassword() {
|
||||||
|
assertThat(
|
||||||
|
assertThrows(
|
||||||
|
IllegalArgumentException.class,
|
||||||
|
() ->
|
||||||
|
new User.Builder()
|
||||||
|
.setUserRoles(new UserRoles.Builder().build())
|
||||||
|
.setRegistryLockPassword("foobar")))
|
||||||
|
.hasMessageThat()
|
||||||
|
.isEqualTo("User has no registry lock permission");
|
||||||
|
|
||||||
|
User user =
|
||||||
|
new User.Builder()
|
||||||
|
.setGaiaId("gaiaId")
|
||||||
|
.setEmailAddress("email@email.com")
|
||||||
|
.setUserRoles(new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build())
|
||||||
|
.build();
|
||||||
|
assertThat(user.hasRegistryLockPassword()).isFalse();
|
||||||
|
|
||||||
|
user = user.asBuilder().setRegistryLockPassword("foobar").build();
|
||||||
|
assertThat(user.hasRegistryLockPassword()).isTrue();
|
||||||
|
assertThat(user.verifyRegistryLockPassword("foobar")).isTrue();
|
||||||
|
|
||||||
|
user = user.asBuilder().removeRegistryLockPassword().build();
|
||||||
|
assertThat(user.hasRegistryLockPassword()).isFalse();
|
||||||
|
assertThat(user.verifyRegistryLockPassword("foobar")).isFalse();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue