mirror of
https://github.com/google/nomulus.git
synced 2025-04-30 12:07:51 +02:00
Allow admins to access registrar console without a RegistrarContact
This allows admins to access the registrar console without needing to be added as a registrar contact. If they are a registrar contact, then that registrar takes precedence. Tested=In Alpha ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164182623
This commit is contained in:
parent
151ae2558f
commit
f3919e056d
9 changed files with 308 additions and 69 deletions
|
@ -171,9 +171,8 @@ upload just that one using the `-M` flag to specify the service to update.
|
||||||
To verify successful deployment, visit
|
To verify successful deployment, visit
|
||||||
https://acme-registry-alpha.appspot.com/registrar in your browser (adjusting
|
https://acme-registry-alpha.appspot.com/registrar in your browser (adjusting
|
||||||
appropriately for the project ID that you actually used). If the project
|
appropriately for the project ID that you actually used). If the project
|
||||||
deployed successfully, you'll see a "You need permission" page indicating that
|
deployed successfully, you'll see the registrar console homepage. It's time to
|
||||||
you need to configure the system and grant access to your Google account. It's
|
go to the next step, configuration.
|
||||||
time to go to the next step, configuration.
|
|
||||||
|
|
||||||
Configuration is handled by editing code, rebuilding the project, and deploying
|
Configuration is handled by editing code, rebuilding the project, and deploying
|
||||||
again. See the [configuration guide](./configuration.md) for more details. Once
|
again. See the [configuration guide](./configuration.md) for more details. Once
|
||||||
|
|
|
@ -931,6 +931,16 @@ public final class RegistryConfig {
|
||||||
return config.registryPolicy.checkApiServletClientId;
|
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
|
@Singleton
|
||||||
@Provides
|
@Provides
|
||||||
static RegistryConfigSettings provideRegistryConfigSettings() {
|
static RegistryConfigSettings provideRegistryConfigSettings() {
|
||||||
|
|
|
@ -78,6 +78,7 @@ public class RegistryConfigSettings {
|
||||||
public String tmchCrlUrl;
|
public String tmchCrlUrl;
|
||||||
public String tmchMarksDbUrl;
|
public String tmchMarksDbUrl;
|
||||||
public String checkApiServletClientId;
|
public String checkApiServletClientId;
|
||||||
|
public String registryAdminClientId;
|
||||||
public String reservedTermsExportDisclaimer;
|
public String reservedTermsExportDisclaimer;
|
||||||
public String whoisDisclaimer;
|
public String whoisDisclaimer;
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,6 +71,11 @@ registryPolicy:
|
||||||
# domain checks.
|
# domain checks.
|
||||||
checkApiServletClientId: TheRegistrar
|
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.
|
# Disclaimer at the top of the exported reserved terms list.
|
||||||
reservedTermsExportDisclaimer: |
|
reservedTermsExportDisclaimer: |
|
||||||
This list contains reserved terms for the TLD. Other terms may be reserved
|
This list contains reserved terms for the TLD. Other terms may be reserved
|
||||||
|
|
|
@ -29,6 +29,7 @@ registryPolicy:
|
||||||
tmchCrlUrl: http://crl.icann.org/tmch.crl
|
tmchCrlUrl: http://crl.icann.org/tmch.crl
|
||||||
tmchMarksDbUrl: https://ry.marksdb.org
|
tmchMarksDbUrl: https://ry.marksdb.org
|
||||||
checkApiServletClientId: placeholder
|
checkApiServletClientId: placeholder
|
||||||
|
registryAdminClientId: placeholder
|
||||||
whoisDisclaimer: |
|
whoisDisclaimer: |
|
||||||
multi-line
|
multi-line
|
||||||
placeholder
|
placeholder
|
||||||
|
|
|
@ -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_MOVED_TEMPORARILY;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
|
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.appengine.api.users.UserService;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
import com.google.common.base.Supplier;
|
import com.google.common.base.Supplier;
|
||||||
|
@ -36,6 +35,7 @@ import google.registry.request.Action;
|
||||||
import google.registry.request.Response;
|
import google.registry.request.Response;
|
||||||
import google.registry.request.auth.Auth;
|
import google.registry.request.auth.Auth;
|
||||||
import google.registry.request.auth.AuthResult;
|
import google.registry.request.auth.AuthResult;
|
||||||
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.security.XsrfTokenManager;
|
import google.registry.security.XsrfTokenManager;
|
||||||
import google.registry.ui.server.SoyTemplateUtils;
|
import google.registry.ui.server.SoyTemplateUtils;
|
||||||
import google.registry.ui.soy.registrar.ConsoleSoyInfo;
|
import google.registry.ui.soy.registrar.ConsoleSoyInfo;
|
||||||
|
@ -97,7 +97,7 @@ public final class ConsoleUiAction implements Runnable {
|
||||||
response.setHeader(LOCATION, location);
|
response.setHeader(LOCATION, location);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
User user = authResult.userAuthInfo().get().user();
|
UserAuthInfo userAuthInfo = authResult.userAuthInfo().get();
|
||||||
response.setContentType(MediaType.HTML_UTF_8);
|
response.setContentType(MediaType.HTML_UTF_8);
|
||||||
response.setHeader(X_FRAME_OPTIONS, "SAMEORIGIN"); // Disallow iframing.
|
response.setHeader(X_FRAME_OPTIONS, "SAMEORIGIN"); // Disallow iframing.
|
||||||
response.setHeader("X-Ui-Compatible", "IE=edge"); // Ask IE not to be silly.
|
response.setHeader("X-Ui-Compatible", "IE=edge"); // Ask IE not to be silly.
|
||||||
|
@ -119,9 +119,9 @@ public final class ConsoleUiAction implements Runnable {
|
||||||
.render());
|
.render());
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
data.put("username", user.getNickname());
|
data.put("username", userAuthInfo.user().getNickname());
|
||||||
data.put("logoutUrl", userService.createLogoutURL(PATH));
|
data.put("logoutUrl", userService.createLogoutURL(PATH));
|
||||||
if (!sessionUtils.checkRegistrarConsoleLogin(req, user)) {
|
if (!sessionUtils.checkRegistrarConsoleLogin(req, userAuthInfo)) {
|
||||||
response.setStatus(SC_FORBIDDEN);
|
response.setStatus(SC_FORBIDDEN);
|
||||||
response.setPayload(
|
response.setPayload(
|
||||||
TOFU_SUPPLIER.get()
|
TOFU_SUPPLIER.get()
|
||||||
|
@ -135,7 +135,7 @@ public final class ConsoleUiAction implements Runnable {
|
||||||
Registrar registrar =
|
Registrar registrar =
|
||||||
checkArgumentPresent(
|
checkArgumentPresent(
|
||||||
Registrar.loadByClientIdCached(clientId), "Registrar %s does not exist", clientId);
|
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("clientId", clientId);
|
||||||
data.put("showPaymentLink", registrar.getBillingMethod() == Registrar.BillingMethod.BRAINTREE);
|
data.put("showPaymentLink", registrar.getBillingMethod() == Registrar.BillingMethod.BRAINTREE);
|
||||||
|
|
||||||
|
|
|
@ -22,12 +22,15 @@ import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
|
||||||
import com.google.appengine.api.users.User;
|
import com.google.appengine.api.users.User;
|
||||||
import com.google.common.base.Optional;
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.base.Predicate;
|
import com.google.common.base.Predicate;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.FluentIterable;
|
import com.google.common.collect.FluentIterable;
|
||||||
import com.googlecode.objectify.Key;
|
import com.googlecode.objectify.Key;
|
||||||
|
import google.registry.config.RegistryConfig.Config;
|
||||||
import google.registry.model.registrar.Registrar;
|
import google.registry.model.registrar.Registrar;
|
||||||
import google.registry.model.registrar.RegistrarContact;
|
import google.registry.model.registrar.RegistrarContact;
|
||||||
import google.registry.request.HttpException.ForbiddenException;
|
import google.registry.request.HttpException.ForbiddenException;
|
||||||
import google.registry.request.auth.AuthResult;
|
import google.registry.request.auth.AuthResult;
|
||||||
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.util.FormattingLogger;
|
import google.registry.util.FormattingLogger;
|
||||||
import javax.annotation.CheckReturnValue;
|
import javax.annotation.CheckReturnValue;
|
||||||
import javax.annotation.Nonnull;
|
import javax.annotation.Nonnull;
|
||||||
|
@ -40,10 +43,14 @@ import javax.servlet.http.HttpSession;
|
||||||
@Immutable
|
@Immutable
|
||||||
public class SessionUtils {
|
public class SessionUtils {
|
||||||
|
|
||||||
private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
|
static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
|
||||||
|
|
||||||
public static final String CLIENT_ID_ATTRIBUTE = "clientId";
|
public static final String CLIENT_ID_ATTRIBUTE = "clientId";
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
@Config("registryAdminClientId")
|
||||||
|
String registryAdminClientId;
|
||||||
|
|
||||||
@Inject public SessionUtils() {}
|
@Inject public SessionUtils() {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -58,7 +65,7 @@ public class SessionUtils {
|
||||||
if (!authResult.userAuthInfo().isPresent()) {
|
if (!authResult.userAuthInfo().isPresent()) {
|
||||||
throw new ForbiddenException("Not logged in");
|
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");
|
throw new ForbiddenException("Not authorized to access Registrar Console");
|
||||||
}
|
}
|
||||||
String clientId = getRegistrarClientId(request);
|
String clientId = getRegistrarClientId(request);
|
||||||
|
@ -86,28 +93,62 @@ public class SessionUtils {
|
||||||
* error response and abort the request.
|
* error response and abort the request.
|
||||||
*/
|
*/
|
||||||
@CheckReturnValue
|
@CheckReturnValue
|
||||||
public boolean checkRegistrarConsoleLogin(HttpServletRequest req, User user) {
|
public boolean checkRegistrarConsoleLogin(HttpServletRequest req, UserAuthInfo userAuthInfo) {
|
||||||
checkState(user != null, "No logged in user found");
|
checkState(userAuthInfo != null, "No logged in user found");
|
||||||
|
User user = userAuthInfo.user();
|
||||||
HttpSession session = req.getSession();
|
HttpSession session = req.getSession();
|
||||||
String clientId = (String) session.getAttribute(CLIENT_ID_ATTRIBUTE);
|
String clientId = (String) session.getAttribute(CLIENT_ID_ATTRIBUTE);
|
||||||
if (clientId == null) {
|
|
||||||
Optional<Registrar> registrar = guessRegistrar(user.getUserId());
|
// Use the clientId if it exists
|
||||||
if (!registrar.isPresent()) {
|
if (clientId != null) {
|
||||||
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 {
|
|
||||||
if (!hasAccessToRegistrar(clientId, user.getUserId())) {
|
if (!hasAccessToRegistrar(clientId, user.getUserId())) {
|
||||||
logger.infofmt("Registrar Console access revoked: %s for %s (%s)",
|
logger.infofmt("Registrar Console access revoked: %s", clientId);
|
||||||
clientId, user.getEmail(), user.getUserId());
|
|
||||||
session.invalidate();
|
session.invalidate();
|
||||||
return false;
|
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> 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. */
|
/** Returns first {@link Registrar} that {@code gaeUserId} is authorized to administer. */
|
||||||
private static Optional<Registrar> guessRegistrar(String gaeUserId) {
|
private static Optional<Registrar> findRegistrarForUser(String gaeUserId) {
|
||||||
RegistrarContact contact = ofy().load()
|
RegistrarContact contact = ofy().load()
|
||||||
.type(RegistrarContact.class)
|
.type(RegistrarContact.class)
|
||||||
.filter("gaeUserId", gaeUserId)
|
.filter("gaeUserId", gaeUserId)
|
||||||
|
@ -141,7 +182,7 @@ public class SessionUtils {
|
||||||
}
|
}
|
||||||
|
|
||||||
/** @see #hasAccessToRegistrar(Registrar, String) */
|
/** @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 = Registrar.loadByClientIdCached(clientId);
|
Optional<Registrar> registrar = Registrar.loadByClientIdCached(clientId);
|
||||||
if (!registrar.isPresent()) {
|
if (!registrar.isPresent()) {
|
||||||
logger.warningfmt("Registrar '%s' disappeared from Datastore!", clientId);
|
logger.warningfmt("Registrar '%s' disappeared from Datastore!", clientId);
|
||||||
|
|
|
@ -70,8 +70,9 @@ public class ConsoleUiActionTest {
|
||||||
action.sessionUtils = sessionUtils;
|
action.sessionUtils = sessionUtils;
|
||||||
action.userService = UserServiceFactory.getUserService();
|
action.userService = UserServiceFactory.getUserService();
|
||||||
action.xsrfTokenManager = new XsrfTokenManager(new FakeClock(), action.userService);
|
action.xsrfTokenManager = new XsrfTokenManager(new FakeClock(), action.userService);
|
||||||
action.authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
|
UserAuthInfo userAuthInfo = UserAuthInfo.create(user, false);
|
||||||
when(sessionUtils.checkRegistrarConsoleLogin(request, user)).thenReturn(true);
|
action.authResult = AuthResult.create(AuthLevel.USER, userAuthInfo);
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
||||||
when(sessionUtils.getRegistrarClientId(request)).thenReturn("TheRegistrar");
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("TheRegistrar");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -109,7 +110,8 @@ public class ConsoleUiActionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUserDoesntHaveAccessToAnyRegistrar_showsWhoAreYouPage() throws Exception {
|
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);
|
.thenReturn(false);
|
||||||
action.run();
|
action.run();
|
||||||
assertThat(response.getPayload()).contains("<h1>You need permission</h1>");
|
assertThat(response.getPayload()).contains("<h1>You need permission</h1>");
|
||||||
|
|
|
@ -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.AppEngineRule.THE_REGISTRAR_GAE_USER_ID;
|
||||||
import static google.registry.testing.DatastoreHelper.deleteResource;
|
import static google.registry.testing.DatastoreHelper.deleteResource;
|
||||||
import static google.registry.testing.DatastoreHelper.loadRegistrar;
|
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.Matchers.eq;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.verify;
|
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.appengine.api.users.User;
|
||||||
import com.google.common.testing.NullPointerTester;
|
import com.google.common.testing.NullPointerTester;
|
||||||
|
import com.google.common.testing.TestLogHandler;
|
||||||
import google.registry.model.registrar.RegistrarContact;
|
import google.registry.model.registrar.RegistrarContact;
|
||||||
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.testing.AppEngineRule;
|
import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.ExceptionRule;
|
import google.registry.testing.ExceptionRule;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
|
import java.util.logging.Level;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import javax.servlet.http.HttpServletResponse;
|
import javax.servlet.http.HttpServletResponse;
|
||||||
import javax.servlet.http.HttpSession;
|
import javax.servlet.http.HttpSession;
|
||||||
|
import org.junit.After;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
import org.junit.Rule;
|
import org.junit.Rule;
|
||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
|
@ -43,60 +49,50 @@ import org.junit.runners.JUnit4;
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class SessionUtilsTest {
|
public class SessionUtilsTest {
|
||||||
|
|
||||||
@Rule
|
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
||||||
public final AppEngineRule appEngine = AppEngineRule.builder()
|
|
||||||
.withDatastore()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
@Rule
|
@Rule public final ExceptionRule thrown = new ExceptionRule();
|
||||||
public final ExceptionRule thrown = new ExceptionRule();
|
|
||||||
|
|
||||||
@Rule
|
@Rule public final InjectRule inject = new InjectRule();
|
||||||
public final InjectRule inject = new InjectRule();
|
|
||||||
|
|
||||||
private final HttpServletRequest req = mock(HttpServletRequest.class);
|
private final HttpServletRequest req = mock(HttpServletRequest.class);
|
||||||
private final HttpServletResponse rsp = mock(HttpServletResponse.class);
|
private final HttpServletResponse rsp = mock(HttpServletResponse.class);
|
||||||
private final HttpSession session = mock(HttpSession.class);
|
private final HttpSession session = mock(HttpSession.class);
|
||||||
|
private final TestLogHandler testLogHandler = new TestLogHandler();
|
||||||
|
|
||||||
private SessionUtils sessionUtils;
|
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
|
@Before
|
||||||
public void before() throws Exception {
|
public void before() throws Exception {
|
||||||
|
SessionUtils.logger.addHandler(testLogHandler);
|
||||||
sessionUtils = new SessionUtils();
|
sessionUtils = new SessionUtils();
|
||||||
|
sessionUtils.registryAdminClientId = ADMIN_CLIENT_ID;
|
||||||
|
persistResource(loadRegistrar(ADMIN_CLIENT_ID));
|
||||||
when(req.getSession()).thenReturn(session);
|
when(req.getSession()).thenReturn(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@After
|
||||||
public void testCheckRegistrarConsoleLogin_authedButNoSession_createsSession() throws Exception {
|
public void after() throws Exception {
|
||||||
assertThat(sessionUtils.checkRegistrarConsoleLogin(req, jart)).isTrue();
|
SessionUtils.logger.removeHandler(testLogHandler);
|
||||||
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<RegistrarContact>());
|
|
||||||
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();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** User needs to be logged in before calling checkRegistrarConsoleLogin */
|
||||||
@Test
|
@Test
|
||||||
public void testCheckRegistrarConsoleLogin_notLoggedIn_throwsIllegalStateException()
|
public void testCheckRegistrarConsoleLogin_notLoggedIn_throwsIllegalStateException()
|
||||||
throws Exception {
|
throws Exception {
|
||||||
|
@ -105,9 +101,193 @@ public class SessionUtilsTest {
|
||||||
boolean unused = sessionUtils.checkRegistrarConsoleLogin(req, null);
|
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
|
@Test
|
||||||
public void testCheckRegistrarConsoleLogin_notAllowed_returnsFalse() throws Exception {
|
public void testCheckRegistrarConsoleLogin_hasSession_noAccess_isNotAdmin() throws Exception {
|
||||||
assertThat(sessionUtils.checkRegistrarConsoleLogin(req, bozo)).isFalse();
|
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<RegistrarContact>());
|
||||||
|
assertThat(SessionUtils.hasAccessToRegistrar(DEFAULT_CLIENT_ID, THE_REGISTRAR_GAE_USER_ID))
|
||||||
|
.isFalse();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
|
Loading…
Add table
Reference in a new issue