Add base object classes for new user/role permissioning model (#1707)

* Add base object classes for new user/role permissioning model

- Adds the permissions themselves
- Adds the six roles that a user may have -- three global, three
  per-registrar
- Adds the mapping from role -> set of permissions
- Adds a UserRoles object to encapsulate the answer to the question of
  "does this user have this permission?"
- Adds a User class as a base to show how we will use the new UserRoles
  object
This commit is contained in:
gbrodman 2022-08-05 14:18:16 -04:00 committed by GitHub
parent a12a716806
commit 6370baf9de
10 changed files with 733 additions and 1 deletions

View file

@ -0,0 +1,67 @@
// Copyright 2022 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.model.console;
/** Permissions that users may have in the UI, either per-registrar or globally. */
public enum ConsolePermission {
/** Add, update, or remove other console users. */
MANAGE_USERS,
/** Add, update, or remove registrars. */
MANAGE_REGISTRARS,
/** Manage related registrars, e.g. when one registrar owns another. */
MANAGE_ACCREDITATION,
/** Set up the EPP connection (e.g. certs). */
CONFIGURE_EPP_CONNECTION,
/** Retrieve the unredacted registrant email from a domain. */
GET_REGISTRANT_EMAIL,
/** Suspend a domain for compliance (non-URS) reasons. */
SUSPEND_DOMAIN,
/** Suspend a domain for the Uniform Rapid Suspension process. */
SUSPEND_DOMAIN_URS,
/** Download a list of domains under management. */
DOWNLOAD_DOMAINS,
/** Change the password for a registrar. */
CHANGE_NOMULUS_PASSWORD,
/** View all possible TLDs. */
VIEW_TLD_PORTFOLIO,
/** Onboarding the registrar(s) to extra programs like registry locking. */
ONBOARD_ADDITIONAL_PROGRAMS,
/** Execute arbitrary EPP commands through the UI. */
EXECUTE_EPP_COMMANDS,
/** Send messages to the registry support team. */
CONTACT_SUPPORT,
/** Access billing and payment details for a registrar. */
ACCESS_BILLING_DETAILS,
/** Access any available documentation about the registry. */
ACCESS_DOCUMENTATION,
/** Change the documentation available in the UI about the registry. */
MANAGE_DOCUMENTATION,
/** Viewing the onboarding status of a registrar on a TLD. */
CHECK_ONBOARDING_STATUS,
/** View premium and/or reserved lists for a TLD. */
VIEW_PREMIUM_RESERVED_LISTS,
/** Sign and/or change legal documents like RRAs. */
UPLOAD_CONTRACTS,
/** Viewing legal documents like RRAs. */
ACCESS_CONTRACTS,
/** View analytics on operations and billing data (possibly TBD). */
VIEW_OPERATIONAL_DATA,
/** Create announcements that can be displayed in the UI. */
SEND_ANNOUNCEMENTS,
/** View announcements in the UI. */
VIEW_ANNOUNCEMENTS,
/** Viewing a record of actions performed in the UI for a particular registrar. */
VIEW_ACTIVITY_LOG
}

View file

@ -0,0 +1,104 @@
// Copyright 2022 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.model.console;
import com.google.common.collect.ImmutableSet;
/**
* Definitions of the {@link ConsolePermission} sets that each role contains.
*
* <p>Note: within the "registry" and "registrar" groupings, permissions expand hierarchically,
* where each role has all the permissions of the role below it plus some others.
*/
public class ConsoleRoleDefinitions {
/** Permissions for a registry support agent. */
static final ImmutableSet<ConsolePermission> SUPPORT_AGENT_PERMISSIONS =
ImmutableSet.of(
ConsolePermission.MANAGE_USERS,
ConsolePermission.MANAGE_ACCREDITATION,
ConsolePermission.CONFIGURE_EPP_CONNECTION,
ConsolePermission.DOWNLOAD_DOMAINS,
ConsolePermission.VIEW_TLD_PORTFOLIO,
ConsolePermission.ONBOARD_ADDITIONAL_PROGRAMS,
ConsolePermission.CONTACT_SUPPORT,
ConsolePermission.ACCESS_BILLING_DETAILS,
ConsolePermission.ACCESS_DOCUMENTATION,
ConsolePermission.SUSPEND_DOMAIN_URS,
ConsolePermission.CHECK_ONBOARDING_STATUS,
ConsolePermission.VIEW_PREMIUM_RESERVED_LISTS,
ConsolePermission.UPLOAD_CONTRACTS,
ConsolePermission.ACCESS_CONTRACTS,
ConsolePermission.VIEW_OPERATIONAL_DATA,
ConsolePermission.SEND_ANNOUNCEMENTS,
ConsolePermission.VIEW_ANNOUNCEMENTS,
ConsolePermission.VIEW_ACTIVITY_LOG);
/** Permissions for a registry support lead. */
static final ImmutableSet<ConsolePermission> SUPPORT_LEAD_PERMISSIONS =
new ImmutableSet.Builder<ConsolePermission>()
.addAll(SUPPORT_AGENT_PERMISSIONS)
.add(
ConsolePermission.MANAGE_REGISTRARS,
ConsolePermission.GET_REGISTRANT_EMAIL,
ConsolePermission.SUSPEND_DOMAIN,
ConsolePermission.EXECUTE_EPP_COMMANDS,
ConsolePermission.MANAGE_DOCUMENTATION)
.build();
/** Permissions for a registry full-time employee. */
static final ImmutableSet<ConsolePermission> FTE_PERMISSIONS =
new ImmutableSet.Builder<ConsolePermission>()
.addAll(SUPPORT_LEAD_PERMISSIONS)
.add(ConsolePermission.CHANGE_NOMULUS_PASSWORD)
.build();
/** Permissions for a registrar partner account manager. */
static final ImmutableSet<ConsolePermission> ACCOUNT_MANAGER_PERMISSIONS =
ImmutableSet.of(
ConsolePermission.DOWNLOAD_DOMAINS,
ConsolePermission.VIEW_TLD_PORTFOLIO,
ConsolePermission.CONTACT_SUPPORT,
ConsolePermission.ACCESS_DOCUMENTATION,
ConsolePermission.VIEW_PREMIUM_RESERVED_LISTS,
ConsolePermission.VIEW_OPERATIONAL_DATA,
ConsolePermission.VIEW_ANNOUNCEMENTS);
/** Permissions for the tech contact of a registrar. */
static final ImmutableSet<ConsolePermission> TECH_CONTACT_PERMISSIONS =
new ImmutableSet.Builder<ConsolePermission>()
.addAll(ACCOUNT_MANAGER_PERMISSIONS)
.add(
ConsolePermission.MANAGE_ACCREDITATION,
ConsolePermission.CONFIGURE_EPP_CONNECTION,
ConsolePermission.CHANGE_NOMULUS_PASSWORD,
ConsolePermission.ONBOARD_ADDITIONAL_PROGRAMS,
ConsolePermission.EXECUTE_EPP_COMMANDS,
ConsolePermission.ACCESS_BILLING_DETAILS,
ConsolePermission.CHECK_ONBOARDING_STATUS,
ConsolePermission.UPLOAD_CONTRACTS,
ConsolePermission.ACCESS_CONTRACTS,
ConsolePermission.VIEW_ACTIVITY_LOG)
.build();
/** Permissions for the primary registrar contact. */
static final ImmutableSet<ConsolePermission> PRIMARY_CONTACT_PERMISSIONS =
new ImmutableSet.Builder<ConsolePermission>()
.addAll(TECH_CONTACT_PERMISSIONS)
.add(ConsolePermission.MANAGE_USERS)
.build();
private ConsoleRoleDefinitions() {}
}

View file

@ -0,0 +1,44 @@
// Copyright 2022 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.model.console;
import static google.registry.model.console.ConsoleRoleDefinitions.FTE_PERMISSIONS;
import static google.registry.model.console.ConsoleRoleDefinitions.SUPPORT_AGENT_PERMISSIONS;
import static google.registry.model.console.ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS;
import com.google.common.collect.ImmutableSet;
/** Roles for registry employees that apply across all registrars. */
public enum GlobalRole {
/** The user has no global role, i.e. they're a registrar partner. */
NONE(ImmutableSet.of()),
/** The user is a registry support agent. */
SUPPORT_AGENT(SUPPORT_AGENT_PERMISSIONS),
/** The user is a registry support lead. */
SUPPORT_LEAD(SUPPORT_LEAD_PERMISSIONS),
/** The user is a registry full-time employee. */
FTE(FTE_PERMISSIONS);
private final ImmutableSet<ConsolePermission> permissions;
GlobalRole(ImmutableSet<ConsolePermission> permissions) {
this.permissions = permissions;
}
public boolean hasPermission(ConsolePermission permission) {
return permissions.contains(permission);
}
}

View file

@ -0,0 +1,42 @@
// Copyright 2022 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.model.console;
import static google.registry.model.console.ConsoleRoleDefinitions.ACCOUNT_MANAGER_PERMISSIONS;
import static google.registry.model.console.ConsoleRoleDefinitions.PRIMARY_CONTACT_PERMISSIONS;
import static google.registry.model.console.ConsoleRoleDefinitions.TECH_CONTACT_PERMISSIONS;
import com.google.common.collect.ImmutableSet;
/** Roles for registrar partners that apply to only one registrar. */
public enum RegistrarRole {
/** The user is a standard account manager at a registrar. */
ACCOUNT_MANAGER(ACCOUNT_MANAGER_PERMISSIONS),
/** The user is a technical contact of a registrar. */
TECH_CONTACT(TECH_CONTACT_PERMISSIONS),
/** The user is the primary contact at a registrar. */
PRIMARY_CONTACT(PRIMARY_CONTACT_PERMISSIONS);
private final ImmutableSet<ConsolePermission> permissions;
RegistrarRole(ImmutableSet<ConsolePermission> permissions) {
this.permissions = permissions;
}
public boolean hasPermission(ConsolePermission permission) {
return permissions.contains(permission);
}
}

View file

@ -0,0 +1,148 @@
// Copyright 2022 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.model.console;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.io.BaseEncoding.base64;
import static google.registry.model.registrar.Registrar.checkValidEmail;
import static google.registry.util.PasswordUtils.SALT_SUPPLIER;
import static google.registry.util.PasswordUtils.hashPassword;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import google.registry.model.Buildable;
import google.registry.model.ImmutableObject;
/** A console user, either a registry employee or a registrar partner. */
public class User extends ImmutableObject implements Buildable {
/** Autogenerated unique ID of this user. */
private long id;
/** GAIA ID associated with the user in question. */
private String gaiaId;
/** Email address of the user in question. */
private String emailAddress;
/** Roles (which grant permissions) associated with this user. */
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
* encoded SHA256 string.
*/
String registryLockPasswordHash;
/** Randomly generated hash salt. */
String registryLockPasswordSalt;
public String getGaiaId() {
return gaiaId;
}
public String getEmailAddress() {
return emailAddress;
}
public UserRoles getUserRoles() {
return userRoles;
}
public boolean isAllowedToSetRegistryLockPassword() {
return allowedToSetRegistryLockPassword;
}
public boolean isRegistryLockAllowed() {
return !isNullOrEmpty(registryLockPasswordHash) && !isNullOrEmpty(registryLockPasswordSalt);
}
public boolean verifyRegistryLockPassword(String registryLockPassword) {
if (isNullOrEmpty(registryLockPassword)
|| isNullOrEmpty(registryLockPasswordSalt)
|| isNullOrEmpty(registryLockPasswordHash)) {
return false;
}
return hashPassword(registryLockPassword, registryLockPasswordSalt)
.equals(registryLockPasswordHash);
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
}
/** Builder for constructing immutable {@link User} objects. */
public static class Builder extends Buildable.Builder<User> {
public Builder() {}
public Builder(User user) {
super(user);
}
public User build() {
checkArgumentNotNull(getInstance().gaiaId, "Gaia ID cannot be null");
checkArgumentNotNull(getInstance().emailAddress, "Email address cannot be null");
checkArgumentNotNull(getInstance().userRoles, "User roles cannot be null");
return super.build();
}
public Builder setGaiaId(String gaiaId) {
checkArgument(!isNullOrEmpty(gaiaId), "Gaia ID cannot be null or empty");
getInstance().gaiaId = gaiaId;
return this;
}
public Builder setEmailAddress(String emailAddress) {
getInstance().emailAddress = checkValidEmail(emailAddress);
return this;
}
public Builder setUserRoles(UserRoles userRoles) {
checkArgumentNotNull(userRoles, "User roles cannot be null");
getInstance().userRoles = userRoles;
return this;
}
public Builder setAllowedToSetRegistryLockPassword(boolean allowedToSetRegistryLockPassword) {
if (allowedToSetRegistryLockPassword) {
getInstance().registryLockPasswordSalt = null;
getInstance().registryLockPasswordHash = null;
}
getInstance().allowedToSetRegistryLockPassword = allowedToSetRegistryLockPassword;
return this;
}
public Builder setRegistryLockPassword(String registryLockPassword) {
checkArgument(
getInstance().allowedToSetRegistryLockPassword,
"Not allowed to set registry lock password for this user");
checkArgument(
!isNullOrEmpty(registryLockPassword), "Registry lock password was null or empty");
getInstance().registryLockPasswordSalt = base64().encode(SALT_SUPPLIER.get());
getInstance().registryLockPasswordHash =
hashPassword(registryLockPassword, getInstance().registryLockPasswordSalt);
getInstance().allowedToSetRegistryLockPassword = false;
return this;
}
}
}

View file

@ -0,0 +1,120 @@
// Copyright 2022 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.model.console;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.google.common.collect.ImmutableMap;
import google.registry.model.Buildable;
import google.registry.model.ImmutableObject;
import java.util.Map;
/**
* Contains the global and per-registrar roles for a given user.
*
* <p>See <a href="https://go/nomulus-console-authz">go/nomulus-console-authz</a> for more
* information.
*/
public class UserRoles extends ImmutableObject implements Buildable {
/** Whether the user is a global admin, who has access to everything. */
private boolean isAdmin = false;
/**
* The global role (e.g. {@link GlobalRole#SUPPORT_AGENT}) that the user has across all
* registrars.
*/
private GlobalRole globalRole = GlobalRole.NONE;
/** Any per-registrar roles that this user may have. */
private Map<String, RegistrarRole> registrarRoles = ImmutableMap.of();
/** Whether the user is a global admin, who has access to everything. */
public boolean isAdmin() {
return isAdmin;
}
/**
* The global role (e.g. {@link GlobalRole#SUPPORT_AGENT}) that the user has across all
* registrars.
*/
public GlobalRole getGlobalRole() {
return globalRole;
}
/** Any per-registrar roles that this user may have. */
public Map<String, RegistrarRole> getRegistrarRoles() {
return ImmutableMap.copyOf(registrarRoles);
}
/** If the user has the given permission either globally or on the given registrar. */
public boolean hasPermission(String registrarId, ConsolePermission permission) {
if (hasGlobalPermission(permission)) {
return true;
}
if (!registrarRoles.containsKey(registrarId)) {
return false;
}
return registrarRoles.get(registrarId).hasPermission(permission);
}
/** If the user has the given permission globally across all registrars. */
public boolean hasGlobalPermission(ConsolePermission permission) {
return isAdmin || globalRole.hasPermission(permission);
}
@Override
public Builder asBuilder() {
return new Builder(clone(this));
}
/** Builder for constructing immutable {@link UserRoles} objects. */
public static class Builder extends Buildable.Builder<UserRoles> {
public Builder() {}
private Builder(UserRoles userRoles) {
super(userRoles);
}
@Override
public UserRoles build() {
// Users should only have a global role or per-registrar roles, not both
checkArgument(
getInstance().globalRole.equals(GlobalRole.NONE)
|| getInstance().registrarRoles.isEmpty(),
"Users cannot have both global and per-registrar roles");
return super.build();
}
public Builder setIsAdmin(boolean isAdmin) {
getInstance().isAdmin = isAdmin;
return this;
}
public Builder setGlobalRole(GlobalRole globalRole) {
checkArgumentNotNull(globalRole, "Global role cannot be null");
getInstance().globalRole = globalRole;
return this;
}
public Builder setRegistrarRoles(Map<String, RegistrarRole> registrarRoles) {
checkArgumentNotNull(registrarRoles, "Registrar roles map cannot be null");
getInstance().registrarRoles = ImmutableMap.copyOf(registrarRoles);
return this;
}
}
}

View file

@ -964,7 +964,7 @@ public class Registrar extends ImmutableObject
}
/** Verifies that the email address in question is not null and has a valid format. */
static String checkValidEmail(String email) {
public static String checkValidEmail(String email) {
checkNotNull(email, "Provided email was null");
try {
InternetAddress internetAddress = new InternetAddress(email, true);

View file

@ -0,0 +1,69 @@
// Copyright 2022 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.model.console;
import static com.google.common.truth.Truth.assertThat;
import org.junit.jupiter.api.Test;
/** Tests for {@link ConsoleRoleDefinitions}. */
public class ConsoleRoleDefinitionsTest {
@Test
void testHierarchicalPermissions_registry() {
// 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.
assertThat(
ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.SUPPORT_AGENT_PERMISSIONS))
.isTrue();
assertThat(
ConsoleRoleDefinitions.SUPPORT_AGENT_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS))
.isFalse();
assertThat(
ConsoleRoleDefinitions.FTE_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS))
.isTrue();
assertThat(
ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.FTE_PERMISSIONS))
.isFalse();
}
@Test
void testHierarchicalPermissions_registrar() {
// 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.
assertThat(
ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.SUPPORT_AGENT_PERMISSIONS))
.isTrue();
assertThat(
ConsoleRoleDefinitions.SUPPORT_AGENT_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS))
.isFalse();
assertThat(
ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.SUPPORT_AGENT_PERMISSIONS))
.isTrue();
assertThat(
ConsoleRoleDefinitions.SUPPORT_AGENT_PERMISSIONS.containsAll(
ConsoleRoleDefinitions.SUPPORT_LEAD_PERMISSIONS))
.isFalse();
}
}

View file

@ -0,0 +1,77 @@
// Copyright 2022 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.model.console;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import com.google.common.collect.ImmutableMap;
import org.junit.jupiter.api.Test;
/** Tests for {@link UserRoles}. */
public class UserRolesTest {
@Test
void testDefaults() {
UserRoles userRoles = new UserRoles.Builder().build();
for (ConsolePermission permission : ConsolePermission.values()) {
assertThat(userRoles.getGlobalRole().hasPermission(permission)).isFalse();
}
assertThat(userRoles.getRegistrarRoles()).isEmpty();
assertThat(userRoles.isAdmin()).isFalse();
}
@Test
void testAdmin_overridesAll() {
UserRoles userRoles = new UserRoles.Builder().setIsAdmin(true).build();
for (ConsolePermission permission : ConsolePermission.values()) {
assertThat(userRoles.hasGlobalPermission(permission)).isTrue();
assertThat(userRoles.hasPermission("TheRegistrar", permission)).isTrue();
}
}
@Test
void testRegistrarPermission_withGlobal() {
UserRoles userRoles = new UserRoles.Builder().setGlobalRole(GlobalRole.FTE).build();
for (ConsolePermission permission : ConsolePermission.values()) {
assertThat(userRoles.hasGlobalPermission(permission)).isTrue();
assertThat(userRoles.hasPermission("TheRegistrar", permission)).isTrue();
}
}
@Test
void testRegistrarRoles() {
UserRoles userRoles =
new UserRoles.Builder()
.setGlobalRole(GlobalRole.NONE)
.setIsAdmin(false)
.setRegistrarRoles(ImmutableMap.of("TheRegistrar", RegistrarRole.PRIMARY_CONTACT))
.build();
assertThat(userRoles.hasPermission("TheRegistrar", ConsolePermission.MANAGE_USERS)).isTrue();
assertThat(userRoles.hasPermission("TheRegistrar", ConsolePermission.SUSPEND_DOMAIN)).isFalse();
assertThat(userRoles.hasPermission("nonexistent", ConsolePermission.MANAGE_USERS)).isFalse();
}
@Test
void testFailure_globalOrPerRegistrar() {
UserRoles.Builder builder =
new UserRoles.Builder()
.setGlobalRole(GlobalRole.SUPPORT_AGENT)
.setRegistrarRoles(ImmutableMap.of("TheRegistrar", RegistrarRole.PRIMARY_CONTACT));
assertThat(assertThrows(IllegalArgumentException.class, builder::build))
.hasMessageThat()
.isEqualTo("Users cannot have both global and per-registrar roles");
}
}

View file

@ -0,0 +1,61 @@
// Copyright 2022 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.model.console;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.jupiter.api.Assertions.assertThrows;
import org.junit.jupiter.api.Test;
/** Tests for {@link User}. */
public class UserTest {
@Test
void testFailure_badInputs() {
User.Builder builder = new User.Builder();
assertThat(assertThrows(IllegalArgumentException.class, () -> builder.setGaiaId(null)))
.hasMessageThat()
.isEqualTo("Gaia ID cannot be null or empty");
assertThat(assertThrows(IllegalArgumentException.class, () -> builder.setEmailAddress("")))
.hasMessageThat()
.isEqualTo("Provided email is not a valid email address");
assertThat(assertThrows(NullPointerException.class, () -> builder.setEmailAddress(null)))
.hasMessageThat()
.isEqualTo("Provided email was null");
assertThat(
assertThrows(
IllegalArgumentException.class, () -> builder.setEmailAddress("invalidEmail")))
.hasMessageThat()
.isEqualTo("Provided email invalidEmail is not a valid email address");
assertThat(assertThrows(IllegalArgumentException.class, () -> builder.setUserRoles(null)))
.hasMessageThat()
.isEqualTo("User roles cannot be null");
assertThat(assertThrows(IllegalArgumentException.class, builder::build))
.hasMessageThat()
.isEqualTo("Gaia ID cannot be null");
builder.setGaiaId("gaiaId");
assertThat(assertThrows(IllegalArgumentException.class, builder::build))
.hasMessageThat()
.isEqualTo("Email address cannot be null");
builder.setEmailAddress("email@email.com");
assertThat(assertThrows(IllegalArgumentException.class, builder::build))
.hasMessageThat()
.isEqualTo("User roles cannot be null");
builder.setUserRoles(new UserRoles.Builder().build());
builder.build();
}
}