mirror of
https://github.com/google/nomulus.git
synced 2025-05-02 13:07:50 +02:00
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:
parent
a12a716806
commit
6370baf9de
10 changed files with 733 additions and 1 deletions
|
@ -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
|
||||||
|
}
|
|
@ -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() {}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
|
@ -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);
|
||||||
|
}
|
||||||
|
}
|
148
core/src/main/java/google/registry/model/console/User.java
Normal file
148
core/src/main/java/google/registry/model/console/User.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
120
core/src/main/java/google/registry/model/console/UserRoles.java
Normal file
120
core/src/main/java/google/registry/model/console/UserRoles.java
Normal 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -964,7 +964,7 @@ public class Registrar extends ImmutableObject
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Verifies that the email address in question is not null and has a valid format. */
|
/** 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");
|
checkNotNull(email, "Provided email was null");
|
||||||
try {
|
try {
|
||||||
InternetAddress internetAddress = new InternetAddress(email, true);
|
InternetAddress internetAddress = new InternetAddress(email, true);
|
||||||
|
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
|
@ -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");
|
||||||
|
}
|
||||||
|
}
|
|
@ -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();
|
||||||
|
}
|
||||||
|
}
|
Loading…
Add table
Reference in a new issue