diff --git a/docs/install.md b/docs/install.md index 5933e8d17..663a89503 100644 --- a/docs/install.md +++ b/docs/install.md @@ -171,9 +171,8 @@ upload just that one using the `-M` flag to specify the service to update. To verify successful deployment, visit https://acme-registry-alpha.appspot.com/registrar in your browser (adjusting appropriately for the project ID that you actually used). If the project -deployed successfully, you'll see a "You need permission" page indicating that -you need to configure the system and grant access to your Google account. It's -time to go to the next step, configuration. +deployed successfully, you'll see the registrar console homepage. It's time to +go to the next step, configuration. Configuration is handled by editing code, rebuilding the project, and deploying again. See the [configuration guide](./configuration.md) for more details. Once diff --git a/java/google/registry/config/RegistryConfig.java b/java/google/registry/config/RegistryConfig.java index 7b836c185..e76dffcb4 100644 --- a/java/google/registry/config/RegistryConfig.java +++ b/java/google/registry/config/RegistryConfig.java @@ -931,6 +931,16 @@ public final class RegistryConfig { return config.registryPolicy.checkApiServletClientId; } + /** + * Returns the clientId of the registrar that admins are automatically logged in as if they + * aren't otherwise associated with one. + */ + @Provides + @Config("registryAdminClientId") + public static String provideRegistryAdminClientId(RegistryConfigSettings config) { + return config.registryPolicy.registryAdminClientId; + } + @Singleton @Provides static RegistryConfigSettings provideRegistryConfigSettings() { diff --git a/java/google/registry/config/RegistryConfigSettings.java b/java/google/registry/config/RegistryConfigSettings.java index d1d90f85f..44380106f 100644 --- a/java/google/registry/config/RegistryConfigSettings.java +++ b/java/google/registry/config/RegistryConfigSettings.java @@ -78,6 +78,7 @@ public class RegistryConfigSettings { public String tmchCrlUrl; public String tmchMarksDbUrl; public String checkApiServletClientId; + public String registryAdminClientId; public String reservedTermsExportDisclaimer; public String whoisDisclaimer; } diff --git a/java/google/registry/config/files/default-config.yaml b/java/google/registry/config/files/default-config.yaml index 8cd99454b..1efe321eb 100644 --- a/java/google/registry/config/files/default-config.yaml +++ b/java/google/registry/config/files/default-config.yaml @@ -71,6 +71,11 @@ registryPolicy: # domain checks. checkApiServletClientId: TheRegistrar + # The registry admin's registrar. Admins are granted permission to log in + # using this registrar automatically if they are not associated with any + # registrar + registryAdminClientId: TheRegistrar + # Disclaimer at the top of the exported reserved terms list. reservedTermsExportDisclaimer: | This list contains reserved terms for the TLD. Other terms may be reserved diff --git a/java/google/registry/config/files/nomulus-config-production-sample.yaml b/java/google/registry/config/files/nomulus-config-production-sample.yaml index 926fa5ea7..3493738b3 100644 --- a/java/google/registry/config/files/nomulus-config-production-sample.yaml +++ b/java/google/registry/config/files/nomulus-config-production-sample.yaml @@ -29,6 +29,7 @@ registryPolicy: tmchCrlUrl: http://crl.icann.org/tmch.crl tmchMarksDbUrl: https://ry.marksdb.org checkApiServletClientId: placeholder + registryAdminClientId: placeholder whoisDisclaimer: | multi-line placeholder diff --git a/java/google/registry/ui/server/registrar/ConsoleUiAction.java b/java/google/registry/ui/server/registrar/ConsoleUiAction.java index d97dc3863..53910d1d5 100644 --- a/java/google/registry/ui/server/registrar/ConsoleUiAction.java +++ b/java/google/registry/ui/server/registrar/ConsoleUiAction.java @@ -21,7 +21,6 @@ import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN; import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY; import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE; -import com.google.appengine.api.users.User; import com.google.appengine.api.users.UserService; import com.google.common.annotations.VisibleForTesting; import com.google.common.base.Supplier; @@ -36,6 +35,7 @@ import google.registry.request.Action; import google.registry.request.Response; import google.registry.request.auth.Auth; import google.registry.request.auth.AuthResult; +import google.registry.request.auth.UserAuthInfo; import google.registry.security.XsrfTokenManager; import google.registry.ui.server.SoyTemplateUtils; import google.registry.ui.soy.registrar.ConsoleSoyInfo; @@ -97,7 +97,7 @@ public final class ConsoleUiAction implements Runnable { response.setHeader(LOCATION, location); return; } - User user = authResult.userAuthInfo().get().user(); + UserAuthInfo userAuthInfo = authResult.userAuthInfo().get(); response.setContentType(MediaType.HTML_UTF_8); response.setHeader(X_FRAME_OPTIONS, "SAMEORIGIN"); // Disallow iframing. response.setHeader("X-Ui-Compatible", "IE=edge"); // Ask IE not to be silly. @@ -119,9 +119,9 @@ public final class ConsoleUiAction implements Runnable { .render()); return; } - data.put("username", user.getNickname()); + data.put("username", userAuthInfo.user().getNickname()); data.put("logoutUrl", userService.createLogoutURL(PATH)); - if (!sessionUtils.checkRegistrarConsoleLogin(req, user)) { + if (!sessionUtils.checkRegistrarConsoleLogin(req, userAuthInfo)) { response.setStatus(SC_FORBIDDEN); response.setPayload( TOFU_SUPPLIER.get() @@ -135,7 +135,7 @@ public final class ConsoleUiAction implements Runnable { Registrar registrar = checkArgumentPresent( Registrar.loadByClientIdCached(clientId), "Registrar %s does not exist", clientId); - data.put("xsrfToken", xsrfTokenManager.generateToken(user.getEmail())); + data.put("xsrfToken", xsrfTokenManager.generateToken(userAuthInfo.user().getEmail())); data.put("clientId", clientId); data.put("showPaymentLink", registrar.getBillingMethod() == Registrar.BillingMethod.BRAINTREE); diff --git a/java/google/registry/ui/server/registrar/SessionUtils.java b/java/google/registry/ui/server/registrar/SessionUtils.java index cea8ba009..34637f616 100644 --- a/java/google/registry/ui/server/registrar/SessionUtils.java +++ b/java/google/registry/ui/server/registrar/SessionUtils.java @@ -22,12 +22,15 @@ import static google.registry.util.PreconditionsUtils.checkArgumentPresent; import com.google.appengine.api.users.User; import com.google.common.base.Optional; import com.google.common.base.Predicate; +import com.google.common.base.Strings; import com.google.common.collect.FluentIterable; import com.googlecode.objectify.Key; +import google.registry.config.RegistryConfig.Config; import google.registry.model.registrar.Registrar; import google.registry.model.registrar.RegistrarContact; import google.registry.request.HttpException.ForbiddenException; import google.registry.request.auth.AuthResult; +import google.registry.request.auth.UserAuthInfo; import google.registry.util.FormattingLogger; import javax.annotation.CheckReturnValue; import javax.annotation.Nonnull; @@ -40,10 +43,14 @@ import javax.servlet.http.HttpSession; @Immutable public class SessionUtils { - private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass(); + static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass(); public static final String CLIENT_ID_ATTRIBUTE = "clientId"; + @Inject + @Config("registryAdminClientId") + String registryAdminClientId; + @Inject public SessionUtils() {} /** @@ -58,7 +65,7 @@ public class SessionUtils { if (!authResult.userAuthInfo().isPresent()) { throw new ForbiddenException("Not logged in"); } - if (!checkRegistrarConsoleLogin(request, authResult.userAuthInfo().get().user())) { + if (!checkRegistrarConsoleLogin(request, authResult.userAuthInfo().get())) { throw new ForbiddenException("Not authorized to access Registrar Console"); } String clientId = getRegistrarClientId(request); @@ -86,28 +93,62 @@ public class SessionUtils { * error response and abort the request. */ @CheckReturnValue - public boolean checkRegistrarConsoleLogin(HttpServletRequest req, User user) { - checkState(user != null, "No logged in user found"); + public boolean checkRegistrarConsoleLogin(HttpServletRequest req, UserAuthInfo userAuthInfo) { + checkState(userAuthInfo != null, "No logged in user found"); + User user = userAuthInfo.user(); HttpSession session = req.getSession(); String clientId = (String) session.getAttribute(CLIENT_ID_ATTRIBUTE); - if (clientId == null) { - Optional registrar = guessRegistrar(user.getUserId()); - if (!registrar.isPresent()) { - logger.infofmt("User not associated with any Registrar: %s (%s)", - user.getUserId(), user.getEmail()); - return false; - } - verify(hasAccessToRegistrar(registrar.get(), user.getUserId())); - session.setAttribute(CLIENT_ID_ATTRIBUTE, registrar.get().getClientId()); - } else { + + // Use the clientId if it exists + if (clientId != null) { if (!hasAccessToRegistrar(clientId, user.getUserId())) { - logger.infofmt("Registrar Console access revoked: %s for %s (%s)", - clientId, user.getEmail(), user.getUserId()); + logger.infofmt("Registrar Console access revoked: %s", clientId); session.invalidate(); return false; } + logger.infofmt("Associating user %s with given registrar %s.", user.getUserId(), clientId); + return true; } - return true; + + // The clientId was null, so let's try and find a registrar this user is associated with + Optional registrar = findRegistrarForUser(user.getUserId()); + if (registrar.isPresent()) { + verify(hasAccessToRegistrar(registrar.get(), user.getUserId())); + logger.infofmt( + "Associating user %s with found registrar %s.", + user.getUserId(), registrar.get().getClientId()); + session.setAttribute(CLIENT_ID_ATTRIBUTE, registrar.get().getClientId()); + return true; + } + + // We couldn't guess the registrar, but maybe the user is an admin and we can use the + // registryAdminClientId + if (userAuthInfo.isUserAdmin()) { + if (Strings.isNullOrEmpty(registryAdminClientId)) { + logger.infofmt( + "Cannot associate admin user %s with configured client Id." + + " ClientId is null or empty.", + user.getUserId()); + return false; + } + if (!Registrar.loadByClientIdCached(registryAdminClientId).isPresent()) { + logger.infofmt( + "Cannot associate admin user %s with configured client Id %s." + + " Registrar does not exist.", + user.getUserId(), registryAdminClientId); + return false; + } + logger.infofmt( + "User %s is an admin with no associated registrar." + + " Automatically associating the user with configured client Id %s.", + user.getUserId(), registryAdminClientId); + session.setAttribute(CLIENT_ID_ATTRIBUTE, registryAdminClientId); + return true; + } + + // We couldn't find any relevant clientId + logger.infofmt("User not associated with any Registrar: %s", user.getUserId()); + return false; } /** @@ -123,7 +164,7 @@ public class SessionUtils { } /** Returns first {@link Registrar} that {@code gaeUserId} is authorized to administer. */ - private static Optional guessRegistrar(String gaeUserId) { + private static Optional findRegistrarForUser(String gaeUserId) { RegistrarContact contact = ofy().load() .type(RegistrarContact.class) .filter("gaeUserId", gaeUserId) @@ -141,7 +182,7 @@ public class SessionUtils { } /** @see #hasAccessToRegistrar(Registrar, String) */ - private static boolean hasAccessToRegistrar(String clientId, final String gaeUserId) { + protected static boolean hasAccessToRegistrar(String clientId, final String gaeUserId) { Optional registrar = Registrar.loadByClientIdCached(clientId); if (!registrar.isPresent()) { logger.warningfmt("Registrar '%s' disappeared from Datastore!", clientId); diff --git a/javatests/google/registry/ui/server/registrar/ConsoleUiActionTest.java b/javatests/google/registry/ui/server/registrar/ConsoleUiActionTest.java index d12ed30f0..dd03bc36c 100644 --- a/javatests/google/registry/ui/server/registrar/ConsoleUiActionTest.java +++ b/javatests/google/registry/ui/server/registrar/ConsoleUiActionTest.java @@ -70,8 +70,9 @@ public class ConsoleUiActionTest { action.sessionUtils = sessionUtils; action.userService = UserServiceFactory.getUserService(); action.xsrfTokenManager = new XsrfTokenManager(new FakeClock(), action.userService); - action.authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false)); - when(sessionUtils.checkRegistrarConsoleLogin(request, user)).thenReturn(true); + UserAuthInfo userAuthInfo = UserAuthInfo.create(user, false); + action.authResult = AuthResult.create(AuthLevel.USER, userAuthInfo); + when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true); when(sessionUtils.getRegistrarClientId(request)).thenReturn("TheRegistrar"); } @@ -109,7 +110,8 @@ public class ConsoleUiActionTest { @Test public void testUserDoesntHaveAccessToAnyRegistrar_showsWhoAreYouPage() throws Exception { - when(sessionUtils.checkRegistrarConsoleLogin(any(HttpServletRequest.class), any(User.class))) + when(sessionUtils.checkRegistrarConsoleLogin( + any(HttpServletRequest.class), any(UserAuthInfo.class))) .thenReturn(false); action.run(); assertThat(response.getPayload()).contains("

You need permission

"); diff --git a/javatests/google/registry/ui/server/registrar/SessionUtilsTest.java b/javatests/google/registry/ui/server/registrar/SessionUtilsTest.java index 35367bed7..17ce018ae 100644 --- a/javatests/google/registry/ui/server/registrar/SessionUtilsTest.java +++ b/javatests/google/registry/ui/server/registrar/SessionUtilsTest.java @@ -18,6 +18,8 @@ import static com.google.common.truth.Truth.assertThat; import static google.registry.testing.AppEngineRule.THE_REGISTRAR_GAE_USER_ID; import static google.registry.testing.DatastoreHelper.deleteResource; import static google.registry.testing.DatastoreHelper.loadRegistrar; +import static google.registry.testing.DatastoreHelper.persistResource; +import static google.registry.testing.LogsSubject.assertAboutLogs; import static org.mockito.Matchers.eq; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; @@ -26,13 +28,17 @@ import static org.mockito.Mockito.when; import com.google.appengine.api.users.User; import com.google.common.testing.NullPointerTester; +import com.google.common.testing.TestLogHandler; import google.registry.model.registrar.RegistrarContact; +import google.registry.request.auth.UserAuthInfo; import google.registry.testing.AppEngineRule; import google.registry.testing.ExceptionRule; import google.registry.testing.InjectRule; +import java.util.logging.Level; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import javax.servlet.http.HttpSession; +import org.junit.After; import org.junit.Before; import org.junit.Rule; import org.junit.Test; @@ -43,60 +49,50 @@ import org.junit.runners.JUnit4; @RunWith(JUnit4.class) public class SessionUtilsTest { - @Rule - public final AppEngineRule appEngine = AppEngineRule.builder() - .withDatastore() - .build(); + @Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build(); - @Rule - public final ExceptionRule thrown = new ExceptionRule(); + @Rule public final ExceptionRule thrown = new ExceptionRule(); - @Rule - public final InjectRule inject = new InjectRule(); + @Rule public final InjectRule inject = new InjectRule(); private final HttpServletRequest req = mock(HttpServletRequest.class); private final HttpServletResponse rsp = mock(HttpServletResponse.class); private final HttpSession session = mock(HttpSession.class); + private final TestLogHandler testLogHandler = new TestLogHandler(); private SessionUtils sessionUtils; - private final User jart = new User("jart@google.com", "google.com", THE_REGISTRAR_GAE_USER_ID); - private final User bozo = new User("bozo@bing.com", "bing.com", "badGaeUserId"); + + private static final UserAuthInfo AUTHORIZED_USER = createAuthInfo(true, false); + private static final UserAuthInfo UNAUTHORIZED_USER = createAuthInfo(false, false); + private static final UserAuthInfo AUTHORIZED_ADMIN = createAuthInfo(true, true); + private static final UserAuthInfo UNAUTHORIZED_ADMIN = createAuthInfo(false, true); + private static final String DEFAULT_CLIENT_ID = "TheRegistrar"; + private static final String ADMIN_CLIENT_ID = "NewRegistrar"; + + private static UserAuthInfo createAuthInfo(boolean isAuthorized, boolean isAdmin) { + return UserAuthInfo.create( + new User( + "user1@google.com", + "google.com", + isAuthorized ? THE_REGISTRAR_GAE_USER_ID : "badGaeUserId"), + isAdmin); + } @Before public void before() throws Exception { + SessionUtils.logger.addHandler(testLogHandler); sessionUtils = new SessionUtils(); + sessionUtils.registryAdminClientId = ADMIN_CLIENT_ID; + persistResource(loadRegistrar(ADMIN_CLIENT_ID)); when(req.getSession()).thenReturn(session); } - @Test - public void testCheckRegistrarConsoleLogin_authedButNoSession_createsSession() throws Exception { - assertThat(sessionUtils.checkRegistrarConsoleLogin(req, jart)).isTrue(); - verify(session).setAttribute(eq("clientId"), eq("TheRegistrar")); - } - - @Test - public void testCheckRegistrarConsoleLogin_authedWithValidSession_doesNothing() throws Exception { - when(session.getAttribute("clientId")).thenReturn("TheRegistrar"); - assertThat(sessionUtils.checkRegistrarConsoleLogin(req, jart)).isTrue(); - verify(session).getAttribute("clientId"); - verifyNoMoreInteractions(session); - } - - @Test - public void testCheckRegistrarConsoleLogin_sessionRevoked_invalidates() throws Exception { - RegistrarContact.updateContacts( - loadRegistrar("TheRegistrar"), new java.util.HashSet()); - when(session.getAttribute("clientId")).thenReturn("TheRegistrar"); - assertThat(sessionUtils.checkRegistrarConsoleLogin(req, jart)).isFalse(); - verify(session).invalidate(); - } - - @Test - public void testCheckRegistrarConsoleLogin_orphanedContactIsDenied() throws Exception { - deleteResource(loadRegistrar("TheRegistrar")); - assertThat(sessionUtils.checkRegistrarConsoleLogin(req, jart)).isFalse(); + @After + public void after() throws Exception { + SessionUtils.logger.removeHandler(testLogHandler); } + /** User needs to be logged in before calling checkRegistrarConsoleLogin */ @Test public void testCheckRegistrarConsoleLogin_notLoggedIn_throwsIllegalStateException() throws Exception { @@ -105,9 +101,193 @@ public class SessionUtilsTest { boolean unused = sessionUtils.checkRegistrarConsoleLogin(req, null); } + /** + * If clientId exists in the session and the user does not have access to that registrar, then no + * access should be granted. + */ @Test - public void testCheckRegistrarConsoleLogin_notAllowed_returnsFalse() throws Exception { - assertThat(sessionUtils.checkRegistrarConsoleLogin(req, bozo)).isFalse(); + public void testCheckRegistrarConsoleLogin_hasSession_noAccess_isNotAdmin() throws Exception { + when(session.getAttribute("clientId")).thenReturn(DEFAULT_CLIENT_ID); + assertThat(sessionUtils.checkRegistrarConsoleLogin(req, UNAUTHORIZED_USER)).isFalse(); + verify(session).invalidate(); + assertAboutLogs() + .that(testLogHandler) + .hasLogAtLevelWithMessage(Level.INFO, "Registrar Console access revoked"); + } + + /** + * If clientId exists in the session and the user does not have access to that registrar, then + * access should be revoked. The admin flag should be ignored. + */ + @Test + public void testCheckRegistrarConsoleLogin_hasSession_noAccess_isAdmin() throws Exception { + when(session.getAttribute("clientId")).thenReturn(DEFAULT_CLIENT_ID); + assertThat(sessionUtils.checkRegistrarConsoleLogin(req, UNAUTHORIZED_ADMIN)).isFalse(); + verify(session).invalidate(); + assertAboutLogs() + .that(testLogHandler) + .hasLogAtLevelWithMessage(Level.INFO, "Registrar Console access revoked"); + } + + /** + * If clientId exists in the session and the user does have access to that registrar, then access + * should be allowed. + */ + @Test + public void testCheckRegistrarConsoleLogin_hasSession_hasAccess_isNotAdmin() throws Exception { + when(session.getAttribute("clientId")).thenReturn(DEFAULT_CLIENT_ID); + assertThat(sessionUtils.checkRegistrarConsoleLogin(req, AUTHORIZED_USER)).isTrue(); + verify(session).getAttribute("clientId"); + verifyNoMoreInteractions(session); + assertAboutLogs() + .that(testLogHandler) + .hasLogAtLevelWithMessage( + Level.INFO, + String.format( + "Associating user %s with given registrar %s.", + AUTHORIZED_USER.user().getUserId(), DEFAULT_CLIENT_ID)); + } + + /** + * If clientId exists in the session and the user does have access to that registrar, then access + * should be allowed. The admin flag should be ignored. + */ + @Test + public void testCheckRegistrarConsoleLogin_hasSession_hasAccess_isAdmin() throws Exception { + when(session.getAttribute("clientId")).thenReturn(DEFAULT_CLIENT_ID); + assertThat(sessionUtils.checkRegistrarConsoleLogin(req, AUTHORIZED_ADMIN)).isTrue(); + verify(session).getAttribute("clientId"); + verifyNoMoreInteractions(session); + assertAboutLogs() + .that(testLogHandler) + .hasLogAtLevelWithMessage( + Level.INFO, + String.format( + "Associating user %s with given registrar %s.", + AUTHORIZED_ADMIN.user().getUserId(), DEFAULT_CLIENT_ID)); + } + + /** + * If clientId does not exist in the session and the user has access to a registrar, then access + * should be granted to that registrar. + */ + @Test + public void testCheckRegistrarConsoleLogin_noSession_hasAccess_isNotAdmin() throws Exception { + assertThat(sessionUtils.checkRegistrarConsoleLogin(req, AUTHORIZED_USER)).isTrue(); + verify(session).setAttribute(eq("clientId"), eq(DEFAULT_CLIENT_ID)); + assertAboutLogs() + .that(testLogHandler) + .hasLogAtLevelWithMessage( + Level.INFO, + String.format( + "Associating user %s with found registrar %s.", + AUTHORIZED_USER.user().getUserId(), DEFAULT_CLIENT_ID)); + } + + /** + * If clientId does not exist in the session and the user has access to a registrar, then access + * should be granted to that registrar. The admin flag should be ignored. + */ + @Test + public void testCheckRegistrarConsoleLogin_noSession_hasAccess_isAdmin() throws Exception { + assertThat(sessionUtils.checkRegistrarConsoleLogin(req, AUTHORIZED_ADMIN)).isTrue(); + verify(session).setAttribute(eq("clientId"), eq(DEFAULT_CLIENT_ID)); + assertAboutLogs() + .that(testLogHandler) + .hasLogAtLevelWithMessage( + Level.INFO, + String.format( + "Associating user %s with found registrar %s.", + AUTHORIZED_ADMIN.user().getUserId(), DEFAULT_CLIENT_ID)); + } + + /** + * If clientId does not exist in the session, the user is not associated with a registrar and the + * user is an admin, then access could be granted to the configured adminClientId. But if the + * configured adminClientId is empty or null, no access is granted. + */ + @Test + public void testCheckRegistrarConsoleLogin_noSession_noAccess_isAdmin_adminClientIdEmpty() + throws Exception { + sessionUtils.registryAdminClientId = ""; + assertThat(sessionUtils.checkRegistrarConsoleLogin(req, UNAUTHORIZED_ADMIN)).isFalse(); + assertAboutLogs() + .that(testLogHandler) + .hasLogAtLevelWithMessage( + Level.INFO, + String.format( + "Cannot associate admin user %s with configured client Id." + + " ClientId is null or empty.", + UNAUTHORIZED_ADMIN.user().getUserId())); + } + + /** + * If clientId does not exist in the session, the user is not associated with a registrar and the + * user is an admin, then access could be granted to the configured adminClientId. But if the + * configured adminClientId does not reference a registry, then no access is granted. + */ + @Test + public void testCheckRegistrarConsoleLogin_noSession_noAccess_isAdmin_adminClientIdInvalid() + throws Exception { + sessionUtils.registryAdminClientId = "NonexistentRegistry"; + assertThat(sessionUtils.checkRegistrarConsoleLogin(req, UNAUTHORIZED_ADMIN)).isFalse(); + assertAboutLogs() + .that(testLogHandler) + .hasLogAtLevelWithMessage( + Level.INFO, + String.format( + "Cannot associate admin user %s with configured client Id %s." + + " Registrar does not exist.", + UNAUTHORIZED_ADMIN.user().getUserId(), "NonexistentRegistry")); + } + + /** + * If clientId does not exist in the session, the user does not have access to a registrar and the + * user is an admin, then grant the user access to the validated configured adminClientId. + */ + @Test + public void testCheckRegistrarConsoleLogin_noSession_noAccess_isAdmin() throws Exception { + assertThat(sessionUtils.checkRegistrarConsoleLogin(req, UNAUTHORIZED_ADMIN)).isTrue(); + verify(session).setAttribute(eq("clientId"), eq(ADMIN_CLIENT_ID)); + assertAboutLogs() + .that(testLogHandler) + .hasLogAtLevelWithMessage( + Level.INFO, + String.format( + "User %s is an admin with no associated registrar." + + " Automatically associating the user with configured client Id %s.", + UNAUTHORIZED_ADMIN.user().getUserId(), ADMIN_CLIENT_ID)); + } + + /** + * If clientId does not exist in the session and the user is not associated with a registrar, then + * access should not be granted. + */ + @Test + public void testCheckRegistrarConsoleLogin_noSession_noAccess_isNotAdmin() throws Exception { + assertThat(sessionUtils.checkRegistrarConsoleLogin(req, UNAUTHORIZED_USER)).isFalse(); + assertAboutLogs() + .that(testLogHandler) + .hasLogAtLevelWithMessage( + Level.INFO, + String.format( + "User not associated with any Registrar: %s", + UNAUTHORIZED_USER.user().getUserId())); + } + + @Test + public void testHasAccessToRegistrar_orphanedContact_returnsFalse() throws Exception { + deleteResource(loadRegistrar(DEFAULT_CLIENT_ID)); + assertThat(SessionUtils.hasAccessToRegistrar(DEFAULT_CLIENT_ID, THE_REGISTRAR_GAE_USER_ID)) + .isFalse(); + } + + @Test + public void testHasAccessToRegistrar_accessRevoked_returnsFalse() throws Exception { + RegistrarContact.updateContacts( + loadRegistrar(DEFAULT_CLIENT_ID), new java.util.HashSet()); + assertThat(SessionUtils.hasAccessToRegistrar(DEFAULT_CLIENT_ID, THE_REGISTRAR_GAE_USER_ID)) + .isFalse(); } @Test