mirror of
https://github.com/google/nomulus.git
synced 2025-07-04 02:03:24 +02:00
Part of the attempt to remove or suppress warnings for deprecated API use, which will make the Gradle project usable with Intellij. Currently in the Intellij/Gradle setup, deprecation warnings cause Intellij build process to fail. Passing -Werror:none flags to javac\ does not have any effect. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=246135737
412 lines
16 KiB
Java
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.ArgumentMatchers.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,
|
|
"Registrar BadClientId does not exist");
|
|
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);
|
|
}
|
|
}
|