google-nomulus/javatests/google/registry/request/auth/AuthenticatedRegistrarAccessorTest.java
mcilwain 8ae2260ed1 Allow registrars to be completely DISABLED
Disabled registrar cannot perform any actions via EPP and cannot log in to the
registrar web console.

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=239606389
2019-03-21 15:03:33 -04:00

412 lines
16 KiB
Java

// Copyright 2018 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.request.auth;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.request.auth.AuthenticatedRegistrarAccessor.Role.ADMIN;
import static google.registry.request.auth.AuthenticatedRegistrarAccessor.Role.OWNER;
import static google.registry.testing.AppEngineRule.THE_REGISTRAR_GAE_USER_ID;
import static google.registry.testing.DatastoreHelper.loadRegistrar;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.testing.JUnitBackports.assertThrows;
import static google.registry.testing.LogsSubject.assertAboutLogs;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyZeroInteractions;
import static org.mockito.Mockito.when;
import com.google.appengine.api.users.User;
import com.google.common.collect.ImmutableSetMultimap;
import com.google.common.flogger.LoggerConfig;
import com.google.common.testing.NullPointerTester;
import com.google.common.testing.TestLogHandler;
import dagger.Lazy;
import google.registry.groups.GroupsConnection;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.Registrar.State;
import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAccessDeniedException;
import google.registry.testing.AppEngineRule;
import google.registry.testing.InjectRule;
import java.util.Optional;
import java.util.logging.Level;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.junit.After;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
/** Unit tests for {@link AuthenticatedRegistrarAccessor}. */
@RunWith(JUnit4.class)
public class AuthenticatedRegistrarAccessorTest {
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
@Rule public final InjectRule inject = new InjectRule();
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
@Mock private HttpServletRequest req;
@Mock private HttpServletResponse rsp;
@Mock private GroupsConnection groupsConnection;
@Mock private Lazy<GroupsConnection> lazyGroupsConnection;
private final TestLogHandler testLogHandler = new TestLogHandler();
private static final AuthResult USER = createAuthResult(false);
private static final AuthResult GAE_ADMIN = createAuthResult(true);
private static final AuthResult NO_USER = AuthResult.create(AuthLevel.NONE);
private static final Optional<String> SUPPORT_GROUP = Optional.of("support@registry.example");
/** Client ID of a REAL registrar with a RegistrarContact for USER and GAE_ADMIN. */
private static final String CLIENT_ID_WITH_CONTACT = "TheRegistrar";
/** Client ID of a REAL registrar without a RegistrarContact. */
private static final String REAL_CLIENT_ID_WITHOUT_CONTACT = "NewRegistrar";
/** Client ID of an OTE registrar without a RegistrarContact. */
private static final String OTE_CLIENT_ID_WITHOUT_CONTACT = "OteRegistrar";
/** Client ID of the Admin registrar without a RegistrarContact. */
private static final String ADMIN_CLIENT_ID = "AdminRegistrar";
/**
* Creates an AuthResult for a fake user.
*
* The user will be a RegistrarContact for "TheRegistrar", but not for "NewRegistrar".
*
* @param isAdmin if true, the user is an administrator for the app-engine project.
*/
private static AuthResult createAuthResult(boolean isAdmin) {
return AuthResult.create(
AuthLevel.USER,
UserAuthInfo.create(
new User(
String.format(
"%s@gmail.com",
isAdmin ? "admin" : "user"),
"gmail.com",
THE_REGISTRAR_GAE_USER_ID),
isAdmin));
}
@Before
public void before() {
when(lazyGroupsConnection.get()).thenReturn(groupsConnection);
LoggerConfig.getConfig(AuthenticatedRegistrarAccessor.class).addHandler(testLogHandler);
// persistResource(loadRegistrar(ADMIN_CLIENT_ID));
persistResource(
loadRegistrar(REAL_CLIENT_ID_WITHOUT_CONTACT)
.asBuilder()
.setClientId(OTE_CLIENT_ID_WITHOUT_CONTACT)
.setType(Registrar.Type.OTE)
.setIanaIdentifier(null)
.build());
persistResource(
loadRegistrar(REAL_CLIENT_ID_WITHOUT_CONTACT)
.asBuilder()
.setClientId(ADMIN_CLIENT_ID)
.setType(Registrar.Type.OTE)
.setIanaIdentifier(null)
.build());
when(groupsConnection.isMemberOfGroup(any(), any())).thenReturn(false);
}
@After
public void after() {
LoggerConfig.getConfig(AuthenticatedRegistrarAccessor.class).removeHandler(testLogHandler);
}
/** Users are owners for registrars if and only if they are in the contacts for that registrar. */
@Test
public void getAllClientIdWithAccess_user() {
AuthenticatedRegistrarAccessor registrarAccessor =
new AuthenticatedRegistrarAccessor(
USER, ADMIN_CLIENT_ID, SUPPORT_GROUP, lazyGroupsConnection);
assertThat(registrarAccessor.getAllClientIdWithRoles())
.containsExactly(CLIENT_ID_WITH_CONTACT, OWNER);
verify(lazyGroupsConnection).get();
}
/** Logged out users don't have access to anything. */
@Test
public void getAllClientIdWithAccess_loggedOutUser() {
AuthenticatedRegistrarAccessor registrarAccessor =
new AuthenticatedRegistrarAccessor(
NO_USER, ADMIN_CLIENT_ID, SUPPORT_GROUP, lazyGroupsConnection);
assertThat(registrarAccessor.getAllClientIdWithRoles()).isEmpty();
verifyZeroInteractions(lazyGroupsConnection);
}
/**
* GAE admins have admin access to everything.
*
* <p>They also have OWNER access if they are in the RegistrarContacts.
*
* <p>They also have OWNER access to the Admin Registrar.
*
* <p>They also have OWNER access to non-REAL Registrars.
*
* <p>(in other words - they don't have OWNER access only to REAL registrars owned by others)
*/
@Test
public void getAllClientIdWithAccess_gaeAdmin() {
AuthenticatedRegistrarAccessor registrarAccessor =
new AuthenticatedRegistrarAccessor(
GAE_ADMIN, ADMIN_CLIENT_ID, SUPPORT_GROUP, lazyGroupsConnection);
assertThat(registrarAccessor.getAllClientIdWithRoles())
.containsExactly(
CLIENT_ID_WITH_CONTACT, ADMIN,
CLIENT_ID_WITH_CONTACT, OWNER,
REAL_CLIENT_ID_WITHOUT_CONTACT, ADMIN,
OTE_CLIENT_ID_WITHOUT_CONTACT, ADMIN,
OTE_CLIENT_ID_WITHOUT_CONTACT, OWNER,
ADMIN_CLIENT_ID, ADMIN,
ADMIN_CLIENT_ID, OWNER);
verifyZeroInteractions(lazyGroupsConnection);
}
/**
* Users in support group have admin access to everything.
*
* <p>They also have OWNER access if they are in the RegistrarContacts.
*
* <p>They also have OWNER access to the Admin Registrar.
*
* <p>They also have OWNER access to non-REAL Registrars.
*
* <p>(in other words - they don't have OWNER access only to REAL registrars owned by others)
*/
@Test
public void getAllClientIdWithAccess_userInSupportGroup() {
when(groupsConnection.isMemberOfGroup("user@gmail.com", SUPPORT_GROUP.get())).thenReturn(true);
AuthenticatedRegistrarAccessor registrarAccessor =
new AuthenticatedRegistrarAccessor(
USER, ADMIN_CLIENT_ID, SUPPORT_GROUP, lazyGroupsConnection);
assertThat(registrarAccessor.getAllClientIdWithRoles())
.containsExactly(
CLIENT_ID_WITH_CONTACT, ADMIN,
CLIENT_ID_WITH_CONTACT, OWNER,
REAL_CLIENT_ID_WITHOUT_CONTACT, ADMIN,
OTE_CLIENT_ID_WITHOUT_CONTACT, ADMIN,
OTE_CLIENT_ID_WITHOUT_CONTACT, OWNER,
ADMIN_CLIENT_ID, ADMIN,
ADMIN_CLIENT_ID, OWNER);
verify(lazyGroupsConnection).get();
}
/** Empty Support group email - skips check and doesn't generate the lazy. */
@Test
public void getAllClientIdWithAccess_emptySupportEmail_works() {
AuthenticatedRegistrarAccessor registrarAccessor =
new AuthenticatedRegistrarAccessor(
USER, ADMIN_CLIENT_ID, Optional.empty(), lazyGroupsConnection);
assertThat(registrarAccessor.getAllClientIdWithRoles())
.containsExactly(CLIENT_ID_WITH_CONTACT, OWNER);
// Make sure we didn't instantiate the lazyGroupsConnection
verifyZeroInteractions(lazyGroupsConnection);
}
/** Support group check throws - continue anyway. */
@Test
public void getAllClientIdWithAccess_throwingGroupCheck_stillWorks() {
when(groupsConnection.isMemberOfGroup(any(), any())).thenThrow(new RuntimeException("blah"));
AuthenticatedRegistrarAccessor registrarAccessor =
new AuthenticatedRegistrarAccessor(
USER, ADMIN_CLIENT_ID, SUPPORT_GROUP, lazyGroupsConnection);
verify(groupsConnection).isMemberOfGroup("user@gmail.com", SUPPORT_GROUP.get());
assertThat(registrarAccessor.getAllClientIdWithRoles())
.containsExactly(CLIENT_ID_WITH_CONTACT, OWNER);
verify(lazyGroupsConnection).get();
}
/** Fail loading registrar if user doesn't have access to it. */
@Test
public void testGetRegistrarForUser_noAccess_isNotAdmin() {
expectGetRegistrarFailure(
REAL_CLIENT_ID_WITHOUT_CONTACT,
USER,
"user user@gmail.com doesn't have access to registrar NewRegistrar");
verify(lazyGroupsConnection).get();
}
@Test
public void testGetRegistrarForUser_registrarIsDisabled_isNotAdmin() {
persistResource(
Registrar.loadByClientId("TheRegistrar")
.get()
.asBuilder()
.setState(State.DISABLED)
.build());
expectGetRegistrarFailure(
CLIENT_ID_WITH_CONTACT,
USER,
"user user@gmail.com doesn't have access to registrar TheRegistrar");
verify(lazyGroupsConnection).get();
}
/** Fail loading registrar if user doesn't have access to it, even if it's not REAL. */
@Test
public void testGetRegistrarForUser_noAccess_isNotAdmin_notReal() {
expectGetRegistrarFailure(
OTE_CLIENT_ID_WITHOUT_CONTACT,
USER,
"user user@gmail.com doesn't have access to registrar OteRegistrar");
verify(lazyGroupsConnection).get();
}
/** Fail loading registrar if there's no user associated with the request. */
@Test
public void testGetRegistrarForUser_noUser() {
expectGetRegistrarFailure(
CLIENT_ID_WITH_CONTACT,
NO_USER,
"<logged-out user> doesn't have access to registrar TheRegistrar");
verifyZeroInteractions(lazyGroupsConnection);
}
/** Succeed loading registrar if user has access to it. */
@Test
public void testGetRegistrarForUser_inContacts_isNotAdmin() throws Exception {
expectGetRegistrarSuccess(
CLIENT_ID_WITH_CONTACT,
USER,
"user user@gmail.com has [OWNER] access to registrar TheRegistrar");
verify(lazyGroupsConnection).get();
}
/** Succeed loading registrar if admin with access. */
@Test
public void testGetRegistrarForUser_inContacts_isAdmin() throws Exception {
expectGetRegistrarSuccess(
CLIENT_ID_WITH_CONTACT,
GAE_ADMIN,
"admin admin@gmail.com has [OWNER, ADMIN] access to registrar TheRegistrar");
verifyZeroInteractions(lazyGroupsConnection);
}
/** Succeed loading registrar for admin even if they aren't on the approved contacts list. */
@Test
public void testGetRegistrarForUser_notInContacts_isAdmin() throws Exception {
expectGetRegistrarSuccess(
REAL_CLIENT_ID_WITHOUT_CONTACT,
GAE_ADMIN,
"admin admin@gmail.com has [ADMIN] access to registrar NewRegistrar.");
verifyZeroInteractions(lazyGroupsConnection);
}
@Test
public void testGetRegistrarForUser_registrarIsDisabled_isAdmin() throws Exception {
persistResource(
Registrar.loadByClientId("NewRegistrar")
.get()
.asBuilder()
.setState(State.DISABLED)
.build());
expectGetRegistrarSuccess(
REAL_CLIENT_ID_WITHOUT_CONTACT,
GAE_ADMIN,
"admin admin@gmail.com has [OWNER, ADMIN] access to registrar NewRegistrar.");
verifyZeroInteractions(lazyGroupsConnection);
}
/** Succeed loading non-REAL registrar for admin. */
@Test
public void testGetRegistrarForUser_notInContacts_isAdmin_notReal() throws Exception {
expectGetRegistrarSuccess(
OTE_CLIENT_ID_WITHOUT_CONTACT,
GAE_ADMIN,
"admin admin@gmail.com has [OWNER, ADMIN] access to registrar OteRegistrar.");
verifyZeroInteractions(lazyGroupsConnection);
}
/** Fail loading registrar even if admin, if registrar doesn't exist. */
@Test
public void testGetRegistrarForUser_doesntExist_isAdmin() {
expectGetRegistrarFailure(
"BadClientId",
GAE_ADMIN,
"admin admin@gmail.com doesn't have access to registrar BadClientId");
verifyZeroInteractions(lazyGroupsConnection);
}
private void expectGetRegistrarSuccess(String clientId, AuthResult authResult, String message)
throws Exception {
AuthenticatedRegistrarAccessor registrarAccessor =
new AuthenticatedRegistrarAccessor(
authResult, ADMIN_CLIENT_ID, SUPPORT_GROUP, lazyGroupsConnection);
// make sure loading the registrar succeeds and returns a value
assertThat(registrarAccessor.getRegistrar(clientId)).isNotNull();
assertAboutLogs().that(testLogHandler).hasLogAtLevelWithMessage(Level.INFO, message);
}
private void expectGetRegistrarFailure(
String clientId, AuthResult authResult, String message) {
AuthenticatedRegistrarAccessor registrarAccessor =
new AuthenticatedRegistrarAccessor(
authResult, ADMIN_CLIENT_ID, SUPPORT_GROUP, lazyGroupsConnection);
// make sure getRegistrar fails
RegistrarAccessDeniedException exception =
assertThrows(
RegistrarAccessDeniedException.class, () -> registrarAccessor.getRegistrar(clientId));
assertThat(exception).hasMessageThat().contains(message);
}
/** guessClientIdForUser returns the first clientId in getAllClientIdWithRoles. */
@Test
public void testGuessClientIdForUser_hasAccess_returnsFirst() throws Exception {
AuthenticatedRegistrarAccessor registrarAccessor =
AuthenticatedRegistrarAccessor.createForTesting(
ImmutableSetMultimap.of(
"clientId-1", OWNER,
"clientId-2", OWNER,
"clientId-2", ADMIN));
assertThat(registrarAccessor.guessClientId()).isEqualTo("clientId-1");
}
/** If a user doesn't have access to any registrars, guess fails. */
@Test
public void testGuessClientIdForUser_noAccess_fails() {
AuthenticatedRegistrarAccessor registrarAccessor =
AuthenticatedRegistrarAccessor.createForTesting(ImmutableSetMultimap.of());
assertThat(assertThrows(RegistrarAccessDeniedException.class, registrarAccessor::guessClientId))
.hasMessageThat()
.isEqualTo("TestUserId isn't associated with any registrar");
}
@Test
public void testNullness() {
new NullPointerTester()
.setDefault(HttpServletRequest.class, req)
.setDefault(HttpServletResponse.class, rsp)
.testAllPublicStaticMethods(AuthenticatedRegistrarAccessor.class);
}
}