mirror of
https://github.com/google/nomulus.git
synced 2025-05-29 17:00:11 +02:00
Refactor SessionUtil, and Add dropdown menu to switch clientId
SessionUtil is renames AuthenticatedRegistrarAccessor, as it's used to access a registrar for an authenticated user. It will now be injected with the AuthResult instead of receiving it in every function call, since there's only one "legal" AuthResult to use. The AccessType names are changed from READ_ONLY/READ_WRITE to READ/UPDATE, as it was confusing that a user could have both READ_ONLY AND READ_WRITE access to the same registrar. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=216958306
This commit is contained in:
parent
bec7a91cfc
commit
8d93cd8edf
19 changed files with 539 additions and 388 deletions
|
@ -18,7 +18,7 @@ import static com.google.common.base.Charsets.UTF_8;
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
import static com.google.common.net.HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN;
|
import static com.google.common.net.HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN;
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
import static google.registry.ui.server.registrar.SessionUtils.AccessType.READ_ONLY;
|
import static google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor.AccessType.READ;
|
||||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
||||||
import static google.registry.util.DomainNameUtils.canonicalizeDomainName;
|
import static google.registry.util.DomainNameUtils.canonicalizeDomainName;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
import static javax.servlet.http.HttpServletResponse.SC_BAD_REQUEST;
|
||||||
|
@ -48,7 +48,7 @@ import google.registry.request.RequestPath;
|
||||||
import google.registry.request.Response;
|
import google.registry.request.Response;
|
||||||
import google.registry.request.auth.AuthResult;
|
import google.registry.request.auth.AuthResult;
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.ui.server.registrar.SessionUtils;
|
import google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
@ -91,7 +91,7 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
@Inject @RequestPath String requestPath;
|
@Inject @RequestPath String requestPath;
|
||||||
@Inject @FullServletPath String fullServletPath;
|
@Inject @FullServletPath String fullServletPath;
|
||||||
@Inject AuthResult authResult;
|
@Inject AuthResult authResult;
|
||||||
@Inject SessionUtils sessionUtils;
|
@Inject AuthenticatedRegistrarAccessor registrarAccessor;
|
||||||
@Inject RdapJsonFormatter rdapJsonFormatter;
|
@Inject RdapJsonFormatter rdapJsonFormatter;
|
||||||
@Inject @Parameter("registrar") Optional<String> registrarParam;
|
@Inject @Parameter("registrar") Optional<String> registrarParam;
|
||||||
@Inject @Parameter("includeDeleted") Optional<Boolean> includeDeletedParam;
|
@Inject @Parameter("includeDeleted") Optional<Boolean> includeDeletedParam;
|
||||||
|
@ -177,12 +177,12 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
/**
|
/**
|
||||||
* Returns a clientId the given user has console access on, or Optional.empty if there is none.
|
* Returns a clientId the given user has console access on, or Optional.empty if there is none.
|
||||||
*/
|
*/
|
||||||
private Optional<String> getAuthorizedClientId(AuthResult authResult) {
|
private Optional<String> getAuthorizedClientId() {
|
||||||
try {
|
try {
|
||||||
String clientId = sessionUtils.guessClientIdForUser(authResult);
|
String clientId = registrarAccessor.guessClientId();
|
||||||
// We load the Registrar to make sure the user has access to it. We don't actually need it,
|
// We load the Registrar to make sure the user has access to it. We don't actually need it,
|
||||||
// we're just checking if an exception is thrown.
|
// we're just checking if an exception is thrown.
|
||||||
sessionUtils.getRegistrarForUserCached(clientId, READ_ONLY, authResult);
|
registrarAccessor.getRegistrarForUserCached(clientId, READ);
|
||||||
return Optional.of(clientId);
|
return Optional.of(clientId);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.atWarning().withCause(e).log(
|
logger.atWarning().withCause(e).log(
|
||||||
|
@ -215,7 +215,7 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
if (userAuthInfo.isUserAdmin()) {
|
if (userAuthInfo.isUserAdmin()) {
|
||||||
return RdapAuthorization.ADMINISTRATOR_AUTHORIZATION;
|
return RdapAuthorization.ADMINISTRATOR_AUTHORIZATION;
|
||||||
}
|
}
|
||||||
Optional<String> clientId = getAuthorizedClientId(authResult);
|
Optional<String> clientId = getAuthorizedClientId();
|
||||||
if (!clientId.isPresent()) {
|
if (!clientId.isPresent()) {
|
||||||
return RdapAuthorization.PUBLIC_AUTHORIZATION;
|
return RdapAuthorization.PUBLIC_AUTHORIZATION;
|
||||||
}
|
}
|
||||||
|
@ -249,7 +249,7 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
if (userAuthInfo.isUserAdmin()) {
|
if (userAuthInfo.isUserAdmin()) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
if (!getAuthorizedClientId(authResult).isPresent()) {
|
if (!getAuthorizedClientId().isPresent()) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -0,0 +1,234 @@
|
||||||
|
// 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.ui.server.registrar;
|
||||||
|
|
||||||
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
|
|
||||||
|
import com.google.appengine.api.users.User;
|
||||||
|
import com.google.common.base.Strings;
|
||||||
|
import com.google.common.collect.ImmutableSetMultimap;
|
||||||
|
import com.google.common.flogger.FluentLogger;
|
||||||
|
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 java.util.Optional;
|
||||||
|
import java.util.function.Function;
|
||||||
|
import javax.annotation.concurrent.Immutable;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Allows access only to {@link Registrar}s the current user has access to.
|
||||||
|
*
|
||||||
|
* <p>A user has read+write access to a Registrar if there exists a {@link RegistrarContact} with
|
||||||
|
* that user's gaeId and the registrar as a parent.
|
||||||
|
*
|
||||||
|
* <p>An admin has in addition read+write access to {@link #registryAdminClientId}.
|
||||||
|
*
|
||||||
|
* <p>An admin also has read access to ALL registrars.
|
||||||
|
*/
|
||||||
|
@Immutable
|
||||||
|
public class AuthenticatedRegistrarAccessor {
|
||||||
|
|
||||||
|
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||||
|
|
||||||
|
/** Type of access we're requesting. */
|
||||||
|
public enum AccessType {
|
||||||
|
READ,
|
||||||
|
UPDATE
|
||||||
|
}
|
||||||
|
|
||||||
|
AuthResult authResult;
|
||||||
|
String registryAdminClientId;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For any AccessType requested - all clientIDs this user is allowed that AccessType on.
|
||||||
|
*
|
||||||
|
* <p>The order is significant, with "more specific to this user" coming first.
|
||||||
|
*/
|
||||||
|
private final ImmutableSetMultimap<AccessType, String> accessMap;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public AuthenticatedRegistrarAccessor(
|
||||||
|
AuthResult authResult, @Config("registryAdminClientId") String registryAdminClientId) {
|
||||||
|
this.authResult = authResult;
|
||||||
|
this.registryAdminClientId = registryAdminClientId;
|
||||||
|
this.accessMap = createAccessMap(authResult, registryAdminClientId);
|
||||||
|
|
||||||
|
logger.atInfo().log(
|
||||||
|
"User %s has the following accesses: %s", authResult.userIdForLogging(), accessMap);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a Registrar IFF the user is authorized.
|
||||||
|
*
|
||||||
|
* <p>Throws a {@link ForbiddenException} if the user is not logged in, or not authorized to
|
||||||
|
* access the requested registrar.
|
||||||
|
*
|
||||||
|
* @param clientId ID of the registrar we request
|
||||||
|
* @param accessType what kind of access do we want for this registrar - just read it or write as
|
||||||
|
* well? (different users might have different access levels)
|
||||||
|
*/
|
||||||
|
public Registrar getRegistrar(String clientId, AccessType accessType) {
|
||||||
|
return getAndAuthorize(Registrar::loadByClientId, clientId, accessType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Loads a Registrar from the cache IFF the user is authorized.
|
||||||
|
*
|
||||||
|
* <p>Throws a {@link ForbiddenException} if the user is not logged in, or not authorized to
|
||||||
|
* access the requested registrar.
|
||||||
|
*
|
||||||
|
* @param clientId ID of the registrar we request
|
||||||
|
* @param accessType what kind of access do we want for this registrar - just read it or write as
|
||||||
|
* well? (different users might have different access levels)
|
||||||
|
*/
|
||||||
|
public Registrar getRegistrarForUserCached(String clientId, AccessType accessType) {
|
||||||
|
return getAndAuthorize(Registrar::loadByClientIdCached, clientId, accessType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* For all {@link AccessType}s, Returns all ClientIds this user is allowed this access.
|
||||||
|
*
|
||||||
|
* <p>Throws a {@link ForbiddenException} if the user is not logged in.
|
||||||
|
*
|
||||||
|
* <p>The result is ordered starting from "most specific to this user".
|
||||||
|
*
|
||||||
|
* <p>If you want to load the {@link Registrar} object from these (or any other) {@code clientId},
|
||||||
|
* in order to perform actions on behalf of a user, you must use {@link #getRegistrar} which makes
|
||||||
|
* sure the user has permissions.
|
||||||
|
*
|
||||||
|
* <p>Note that this is an OPTIONAL step in the authentication - only used if we don't have any
|
||||||
|
* other clue as to the requested {@code clientId}. It is perfectly OK to get a {@code clientId}
|
||||||
|
* from any other source, as long as the registrar is then loaded using {@link #getRegistrar}.
|
||||||
|
*/
|
||||||
|
public ImmutableSetMultimap<AccessType, String> getAllClientIdWithAccess() {
|
||||||
|
verifyLoggedIn();
|
||||||
|
return accessMap;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* "Guesses" which client ID the user wants from all those they have access to.
|
||||||
|
*
|
||||||
|
* <p>If no such ClientIds exist, throws a ForbiddenException.
|
||||||
|
*
|
||||||
|
* <p>This should be the ClientId "most likely wanted by the user".
|
||||||
|
*
|
||||||
|
* <p>If you want to load the {@link Registrar} object from this (or any other) {@code clientId},
|
||||||
|
* in order to perform actions on behalf of a user, you must use {@link #getRegistrar} which makes
|
||||||
|
* sure the user has permissions.
|
||||||
|
*
|
||||||
|
* <p>Note that this is an OPTIONAL step in the authentication - only used if we don't have any
|
||||||
|
* other clue as to the requested {@code clientId}. It is perfectly OK to get a {@code clientId}
|
||||||
|
* from any other source, as long as the registrar is then loaded using {@link #getRegistrar}.
|
||||||
|
*/
|
||||||
|
public String guessClientId() {
|
||||||
|
verifyLoggedIn();
|
||||||
|
return getAllClientIdWithAccess().values().stream()
|
||||||
|
.findFirst()
|
||||||
|
.orElseThrow(
|
||||||
|
() ->
|
||||||
|
new ForbiddenException(
|
||||||
|
String.format(
|
||||||
|
"User %s isn't associated with any registrar",
|
||||||
|
authResult.userIdForLogging())));
|
||||||
|
}
|
||||||
|
|
||||||
|
private Registrar getAndAuthorize(
|
||||||
|
Function<String, Optional<Registrar>> registrarLoader,
|
||||||
|
String clientId,
|
||||||
|
AccessType accessType) {
|
||||||
|
verifyLoggedIn();
|
||||||
|
|
||||||
|
if (!accessMap.containsEntry(accessType, clientId)) {
|
||||||
|
throw new ForbiddenException(
|
||||||
|
String.format(
|
||||||
|
"User %s doesn't have %s access to registrar %s",
|
||||||
|
authResult.userIdForLogging(), accessType, clientId));
|
||||||
|
}
|
||||||
|
|
||||||
|
Registrar registrar =
|
||||||
|
registrarLoader
|
||||||
|
.apply(clientId)
|
||||||
|
.orElseThrow(
|
||||||
|
() -> new ForbiddenException(String.format("Registrar %s not found", clientId)));
|
||||||
|
|
||||||
|
if (!clientId.equals(registrar.getClientId())) {
|
||||||
|
logger.atSevere().log(
|
||||||
|
"registrarLoader.apply(clientId) returned a Registrar with a different clientId. "
|
||||||
|
+ "Requested: %s, returned: %s.",
|
||||||
|
clientId, registrar.getClientId());
|
||||||
|
throw new ForbiddenException("Internal error - please check logs");
|
||||||
|
}
|
||||||
|
|
||||||
|
logger.atInfo().log(
|
||||||
|
"User %s has %s access to registrar %s.",
|
||||||
|
authResult.userIdForLogging(), accessType, clientId);
|
||||||
|
return registrar;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ImmutableSetMultimap<AccessType, String> createAccessMap(
|
||||||
|
AuthResult authResult, String registryAdminClientId) {
|
||||||
|
|
||||||
|
if (!authResult.userAuthInfo().isPresent()) {
|
||||||
|
return ImmutableSetMultimap.of();
|
||||||
|
}
|
||||||
|
|
||||||
|
UserAuthInfo userAuthInfo = authResult.userAuthInfo().get();
|
||||||
|
|
||||||
|
boolean isAdmin = userAuthInfo.isUserAdmin();
|
||||||
|
User user = userAuthInfo.user();
|
||||||
|
|
||||||
|
ImmutableSetMultimap.Builder<AccessType, String> builder = new ImmutableSetMultimap.Builder<>();
|
||||||
|
|
||||||
|
ofy()
|
||||||
|
.load()
|
||||||
|
.type(RegistrarContact.class)
|
||||||
|
.filter("gaeUserId", user.getUserId())
|
||||||
|
.forEach(
|
||||||
|
contact ->
|
||||||
|
builder
|
||||||
|
.put(AccessType.UPDATE, contact.getParent().getName())
|
||||||
|
.put(AccessType.READ, contact.getParent().getName()));
|
||||||
|
if (isAdmin && !Strings.isNullOrEmpty(registryAdminClientId)) {
|
||||||
|
logger.atInfo().log(
|
||||||
|
"Giving admin %s read+write access to admin registrar %s",
|
||||||
|
authResult.userIdForLogging(), registryAdminClientId);
|
||||||
|
builder
|
||||||
|
.put(AccessType.UPDATE, registryAdminClientId)
|
||||||
|
.put(AccessType.READ, registryAdminClientId);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (isAdmin) {
|
||||||
|
// Admins have READ access to all registrars
|
||||||
|
logger.atInfo().log(
|
||||||
|
"Giving admin %s read-only access to all registrars", authResult.userIdForLogging());
|
||||||
|
ofy()
|
||||||
|
.load()
|
||||||
|
.type(Registrar.class)
|
||||||
|
.forEach(registrar -> builder.put(AccessType.READ, registrar.getClientId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void verifyLoggedIn() {
|
||||||
|
if (!authResult.userAuthInfo().isPresent()) {
|
||||||
|
throw new ForbiddenException("Not logged in");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,8 +16,9 @@ package google.registry.ui.server.registrar;
|
||||||
|
|
||||||
import static com.google.common.net.HttpHeaders.LOCATION;
|
import static com.google.common.net.HttpHeaders.LOCATION;
|
||||||
import static com.google.common.net.HttpHeaders.X_FRAME_OPTIONS;
|
import static com.google.common.net.HttpHeaders.X_FRAME_OPTIONS;
|
||||||
|
import static google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor.AccessType.READ;
|
||||||
|
import static google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor.AccessType.UPDATE;
|
||||||
import static google.registry.ui.server.registrar.RegistrarConsoleModule.PARAM_CLIENT_ID;
|
import static google.registry.ui.server.registrar.RegistrarConsoleModule.PARAM_CLIENT_ID;
|
||||||
import static google.registry.ui.server.registrar.SessionUtils.AccessType.READ_ONLY;
|
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
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;
|
||||||
|
@ -26,6 +27,7 @@ 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;
|
||||||
|
import com.google.common.collect.Sets;
|
||||||
import com.google.common.flogger.FluentLogger;
|
import com.google.common.flogger.FluentLogger;
|
||||||
import com.google.common.io.Resources;
|
import com.google.common.io.Resources;
|
||||||
import com.google.common.net.MediaType;
|
import com.google.common.net.MediaType;
|
||||||
|
@ -71,7 +73,7 @@ public final class ConsoleUiAction implements Runnable {
|
||||||
|
|
||||||
@Inject HttpServletRequest req;
|
@Inject HttpServletRequest req;
|
||||||
@Inject Response response;
|
@Inject Response response;
|
||||||
@Inject SessionUtils sessionUtils;
|
@Inject AuthenticatedRegistrarAccessor registrarAccessor;
|
||||||
@Inject UserService userService;
|
@Inject UserService userService;
|
||||||
@Inject XsrfTokenManager xsrfTokenManager;
|
@Inject XsrfTokenManager xsrfTokenManager;
|
||||||
@Inject AuthResult authResult;
|
@Inject AuthResult authResult;
|
||||||
|
@ -131,9 +133,16 @@ public final class ConsoleUiAction implements Runnable {
|
||||||
data.put("logoutUrl", userService.createLogoutURL(PATH));
|
data.put("logoutUrl", userService.createLogoutURL(PATH));
|
||||||
data.put("xsrfToken", xsrfTokenManager.generateToken(user.getEmail()));
|
data.put("xsrfToken", xsrfTokenManager.generateToken(user.getEmail()));
|
||||||
try {
|
try {
|
||||||
String clientId =
|
String clientId = paramClientId.orElse(registrarAccessor.guessClientId());
|
||||||
paramClientId.orElseGet(() -> sessionUtils.guessClientIdForUser(authResult));
|
|
||||||
data.put("clientId", clientId);
|
data.put("clientId", clientId);
|
||||||
|
|
||||||
|
data.put("readWriteClientIds", registrarAccessor.getAllClientIdWithAccess().get(UPDATE));
|
||||||
|
data.put(
|
||||||
|
"readOnlyClientIds",
|
||||||
|
Sets.difference(
|
||||||
|
registrarAccessor.getAllClientIdWithAccess().get(READ),
|
||||||
|
registrarAccessor.getAllClientIdWithAccess().get(UPDATE)));
|
||||||
|
|
||||||
// We want to load the registrar even if we won't use it later (even if we remove the
|
// We want to load the registrar even if we won't use it later (even if we remove the
|
||||||
// requireFeeExtension) - to make sure the user indeed has access to the guessed registrar.
|
// requireFeeExtension) - to make sure the user indeed has access to the guessed registrar.
|
||||||
//
|
//
|
||||||
|
@ -141,7 +150,7 @@ public final class ConsoleUiAction implements Runnable {
|
||||||
// since we double check the access to the registrar on any read / update request. We have to
|
// since we double check the access to the registrar on any read / update request. We have to
|
||||||
// - since the access might get revoked between the initial page load and the request! (also
|
// - since the access might get revoked between the initial page load and the request! (also
|
||||||
// because the requests come from the browser, and can easily be faked)
|
// because the requests come from the browser, and can easily be faked)
|
||||||
Registrar registrar = sessionUtils.getRegistrarForUser(clientId, READ_ONLY, authResult);
|
Registrar registrar = registrarAccessor.getRegistrar(clientId, READ);
|
||||||
data.put("requireFeeExtension", registrar.getPremiumPriceAckRequired());
|
data.put("requireFeeExtension", registrar.getPremiumPriceAckRequired());
|
||||||
} catch (ForbiddenException e) {
|
} catch (ForbiddenException e) {
|
||||||
logger.atWarning().withCause(e).log(
|
logger.atWarning().withCause(e).log(
|
||||||
|
|
|
@ -20,8 +20,8 @@ import static google.registry.export.sheet.SyncRegistrarsSheetAction.enqueueRegi
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||||
import static google.registry.security.JsonResponseHelper.Status.ERROR;
|
import static google.registry.security.JsonResponseHelper.Status.ERROR;
|
||||||
import static google.registry.security.JsonResponseHelper.Status.SUCCESS;
|
import static google.registry.security.JsonResponseHelper.Status.SUCCESS;
|
||||||
import static google.registry.ui.server.registrar.SessionUtils.AccessType.READ_ONLY;
|
import static google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor.AccessType.READ;
|
||||||
import static google.registry.ui.server.registrar.SessionUtils.AccessType.READ_WRITE;
|
import static google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor.AccessType.UPDATE;
|
||||||
|
|
||||||
import com.google.common.base.Strings;
|
import com.google.common.base.Strings;
|
||||||
import com.google.common.collect.HashMultimap;
|
import com.google.common.collect.HashMultimap;
|
||||||
|
@ -34,13 +34,11 @@ import com.google.common.flogger.FluentLogger;
|
||||||
import google.registry.config.RegistryConfig.Config;
|
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.model.registrar.RegistrarContact.Builder;
|
|
||||||
import google.registry.model.registrar.RegistrarContact.Type;
|
import google.registry.model.registrar.RegistrarContact.Type;
|
||||||
import google.registry.request.Action;
|
import google.registry.request.Action;
|
||||||
import google.registry.request.HttpException.BadRequestException;
|
import google.registry.request.HttpException.BadRequestException;
|
||||||
import google.registry.request.JsonActionRunner;
|
import google.registry.request.JsonActionRunner;
|
||||||
import google.registry.request.auth.Auth;
|
import google.registry.request.auth.Auth;
|
||||||
import google.registry.request.auth.AuthResult;
|
|
||||||
import google.registry.security.JsonResponseHelper;
|
import google.registry.security.JsonResponseHelper;
|
||||||
import google.registry.ui.forms.FormException;
|
import google.registry.ui.forms.FormException;
|
||||||
import google.registry.ui.forms.FormFieldException;
|
import google.registry.ui.forms.FormFieldException;
|
||||||
|
@ -79,9 +77,9 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||||
|
|
||||||
@Inject JsonActionRunner jsonActionRunner;
|
@Inject JsonActionRunner jsonActionRunner;
|
||||||
@Inject AppEngineServiceUtils appEngineServiceUtils;
|
@Inject AppEngineServiceUtils appEngineServiceUtils;
|
||||||
@Inject AuthResult authResult;
|
|
||||||
@Inject SendEmailUtils sendEmailUtils;
|
@Inject SendEmailUtils sendEmailUtils;
|
||||||
@Inject SessionUtils sessionUtils;
|
@Inject AuthenticatedRegistrarAccessor registrarAccessor;
|
||||||
|
|
||||||
@Inject @Config("registrarChangesNotificationEmailAddresses") ImmutableList<String>
|
@Inject @Config("registrarChangesNotificationEmailAddresses") ImmutableList<String>
|
||||||
registrarChangesNotificationEmailAddresses;
|
registrarChangesNotificationEmailAddresses;
|
||||||
@Inject RegistrarSettingsAction() {}
|
@Inject RegistrarSettingsAction() {}
|
||||||
|
@ -134,9 +132,7 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||||
|
|
||||||
Map<String, Object> read(String clientId) {
|
Map<String, Object> read(String clientId) {
|
||||||
return JsonResponseHelper.create(
|
return JsonResponseHelper.create(
|
||||||
SUCCESS,
|
SUCCESS, "Success", registrarAccessor.getRegistrar(clientId, READ).toJsonMap());
|
||||||
"Success",
|
|
||||||
sessionUtils.getRegistrarForUser(clientId, READ_ONLY, authResult).toJsonMap());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Map<String, Object> update(final Map<String, ?> args, String clientId) {
|
Map<String, Object> update(final Map<String, ?> args, String clientId) {
|
||||||
|
@ -146,8 +142,7 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||||
// We load the registrar here rather than outside of the transaction - to make
|
// We load the registrar here rather than outside of the transaction - to make
|
||||||
// sure we have the latest version. This one is loaded inside the transaction, so it's
|
// sure we have the latest version. This one is loaded inside the transaction, so it's
|
||||||
// guaranteed to not change before we update it.
|
// guaranteed to not change before we update it.
|
||||||
Registrar registrar =
|
Registrar registrar = registrarAccessor.getRegistrar(clientId, UPDATE);
|
||||||
sessionUtils.getRegistrarForUser(clientId, READ_WRITE, authResult);
|
|
||||||
// Verify that the registrar hasn't been changed.
|
// Verify that the registrar hasn't been changed.
|
||||||
// To do that - we find the latest update time (or null if the registrar has been
|
// To do that - we find the latest update time (or null if the registrar has been
|
||||||
// deleted) and compare to the update time from the args. The update time in the args
|
// deleted) and compare to the update time from the args. The update time in the args
|
||||||
|
@ -263,7 +258,8 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
|
||||||
Registrar registrar, Map<String, ?> args) {
|
Registrar registrar, Map<String, ?> args) {
|
||||||
|
|
||||||
ImmutableSet.Builder<RegistrarContact> contacts = new ImmutableSet.Builder<>();
|
ImmutableSet.Builder<RegistrarContact> contacts = new ImmutableSet.Builder<>();
|
||||||
Optional<List<Builder>> builders = RegistrarFormFields.CONTACTS_FIELD.extractUntyped(args);
|
Optional<List<RegistrarContact.Builder>> builders =
|
||||||
|
RegistrarFormFields.CONTACTS_FIELD.extractUntyped(args);
|
||||||
if (builders.isPresent()) {
|
if (builders.isPresent()) {
|
||||||
builders.get().forEach(c -> contacts.add(c.setParent(registrar).build()));
|
builders.get().forEach(c -> contacts.add(c.setParent(registrar).build()));
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,199 +0,0 @@
|
||||||
// Copyright 2017 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.ui.server.registrar;
|
|
||||||
|
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
|
||||||
|
|
||||||
import com.google.appengine.api.users.User;
|
|
||||||
import com.google.common.base.Strings;
|
|
||||||
import com.google.common.flogger.FluentLogger;
|
|
||||||
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 java.util.Optional;
|
|
||||||
import java.util.function.Function;
|
|
||||||
import javax.annotation.concurrent.Immutable;
|
|
||||||
import javax.inject.Inject;
|
|
||||||
|
|
||||||
/** HTTP session management helper class. */
|
|
||||||
@Immutable
|
|
||||||
public class SessionUtils {
|
|
||||||
|
|
||||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
@Config("registryAdminClientId")
|
|
||||||
String registryAdminClientId;
|
|
||||||
|
|
||||||
@Inject
|
|
||||||
public SessionUtils() {}
|
|
||||||
|
|
||||||
/** Type of access we're requesting. */
|
|
||||||
public enum AccessType {READ_ONLY, READ_WRITE}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads Registrar on behalf of an authorised user.
|
|
||||||
*
|
|
||||||
* <p>Throws a {@link ForbiddenException} if the user is not logged in, or not authorized to
|
|
||||||
* access the requested registrar.
|
|
||||||
*
|
|
||||||
* @param clientId ID of the registrar we request
|
|
||||||
* @param accessType what kind of access do we want for this registrar - just read it or write as
|
|
||||||
* well? (different users might have different access levels)
|
|
||||||
* @param authResult AuthResult of the user on behalf of which we want to access the data
|
|
||||||
*/
|
|
||||||
public Registrar getRegistrarForUser(
|
|
||||||
String clientId, AccessType accessType, AuthResult authResult) {
|
|
||||||
return getAndAuthorize(Registrar::loadByClientId, clientId, accessType, authResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Loads a Registrar from the cache on behalf of an authorised user.
|
|
||||||
*
|
|
||||||
* <p>Throws a {@link ForbiddenException} if the user is not logged in, or not authorized to
|
|
||||||
* access the requested registrar.
|
|
||||||
*
|
|
||||||
* @param clientId ID of the registrar we request
|
|
||||||
* @param accessType what kind of access do we want for this registrar - just read it or write as
|
|
||||||
* well? (different users might have different access levels)
|
|
||||||
* @param authResult AuthResult of the user on behalf of which we want to access the data
|
|
||||||
*/
|
|
||||||
public Registrar getRegistrarForUserCached(
|
|
||||||
String clientId, AccessType accessType, AuthResult authResult) {
|
|
||||||
return getAndAuthorize(Registrar::loadByClientIdCached, clientId, accessType, authResult);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Registrar getAndAuthorize(
|
|
||||||
Function<String, Optional<Registrar>> registrarLoader,
|
|
||||||
String clientId,
|
|
||||||
AccessType accessType,
|
|
||||||
AuthResult authResult) {
|
|
||||||
UserAuthInfo userAuthInfo =
|
|
||||||
authResult.userAuthInfo().orElseThrow(() -> new ForbiddenException("Not logged in"));
|
|
||||||
boolean isAdmin = userAuthInfo.isUserAdmin();
|
|
||||||
User user = userAuthInfo.user();
|
|
||||||
String userIdForLogging = authResult.userIdForLogging();
|
|
||||||
|
|
||||||
Registrar registrar =
|
|
||||||
registrarLoader
|
|
||||||
.apply(clientId)
|
|
||||||
.orElseThrow(
|
|
||||||
() -> new ForbiddenException(String.format("Registrar %s not found", clientId)));
|
|
||||||
|
|
||||||
if (isInAllowedContacts(registrar, user)) {
|
|
||||||
logger.atInfo().log("User %s has access to registrar %s.", userIdForLogging, clientId);
|
|
||||||
return registrar;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isAdmin && clientId.equals(registryAdminClientId)) {
|
|
||||||
// Admins have access to the registryAdminClientId even if they aren't explicitly in the
|
|
||||||
// allowed contacts
|
|
||||||
logger.atInfo().log("Allowing admin %s access to registrar %s.", userIdForLogging, clientId);
|
|
||||||
return registrar;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isAdmin && accessType == AccessType.READ_ONLY) {
|
|
||||||
// Admins have read-only access to all registrars
|
|
||||||
logger.atInfo().log(
|
|
||||||
"Allowing admin %s read-only access to registrar %s.", userIdForLogging, clientId);
|
|
||||||
return registrar;
|
|
||||||
}
|
|
||||||
|
|
||||||
throw new ForbiddenException(
|
|
||||||
String.format(
|
|
||||||
"User %s doesn't have %s access to registrar %s",
|
|
||||||
userIdForLogging, accessType, clientId));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to guess the {@link Registrar} with which the user is associated.
|
|
||||||
*
|
|
||||||
* <p>Returns the {@code clientId} of a {@link Registrar} the user has access to (is on the
|
|
||||||
* contact list). If the user has access to multiple {@link Registrar}s, an arbitrary one is
|
|
||||||
* selected. If the user is an admin without access to any {@link Registrar}s, {@link
|
|
||||||
* #registryAdminClientId} is returned if it is defined.
|
|
||||||
*
|
|
||||||
* <p>If no {@code clientId} is found, throws a {@link ForbiddenException}.
|
|
||||||
*
|
|
||||||
* <p>If you want to load the {@link Registrar} object from this (or any other) {@code clientId},
|
|
||||||
* in order to perform actions on behalf of a user, you must use {@link #getRegistrarForUser}
|
|
||||||
* which makes sure the user has permissions.
|
|
||||||
*
|
|
||||||
* <p>Note that this is an OPTIONAL step in the authentication - only used if we don't have any
|
|
||||||
* other clue as to the requested {@code clientId}. It is perfectly OK to get a {@code clientId}
|
|
||||||
* from any other source, as long as the registrar is then loaded using {@link
|
|
||||||
* #getRegistrarForUser}.
|
|
||||||
*/
|
|
||||||
public String guessClientIdForUser(AuthResult authResult) {
|
|
||||||
|
|
||||||
UserAuthInfo userAuthInfo =
|
|
||||||
authResult.userAuthInfo().orElseThrow(() -> new ForbiddenException("No logged in"));
|
|
||||||
boolean isAdmin = userAuthInfo.isUserAdmin();
|
|
||||||
User user = userAuthInfo.user();
|
|
||||||
String userIdForLogging = authResult.userIdForLogging();
|
|
||||||
|
|
||||||
RegistrarContact contact =
|
|
||||||
ofy()
|
|
||||||
.load()
|
|
||||||
.type(RegistrarContact.class)
|
|
||||||
.filter("gaeUserId", user.getUserId())
|
|
||||||
.first()
|
|
||||||
.now();
|
|
||||||
if (contact != null) {
|
|
||||||
String registrarClientId = contact.getParent().getName();
|
|
||||||
logger.atInfo().log(
|
|
||||||
"Associating user %s with found registrar %s.", userIdForLogging, registrarClientId);
|
|
||||||
return registrarClientId;
|
|
||||||
}
|
|
||||||
|
|
||||||
// We couldn't find the registrar, but maybe the user is an admin and we can use the
|
|
||||||
// registryAdminClientId
|
|
||||||
if (isAdmin) {
|
|
||||||
if (!Strings.isNullOrEmpty(registryAdminClientId)) {
|
|
||||||
logger.atInfo().log(
|
|
||||||
"User %s is an admin with no associated registrar."
|
|
||||||
+ " Automatically associating the user with configured client Id %s.",
|
|
||||||
userIdForLogging, registryAdminClientId);
|
|
||||||
return registryAdminClientId;
|
|
||||||
}
|
|
||||||
logger.atInfo().log(
|
|
||||||
"Cannot associate admin user %s with configured client Id."
|
|
||||||
+ " ClientId is null or empty.",
|
|
||||||
userIdForLogging);
|
|
||||||
}
|
|
||||||
|
|
||||||
// We couldn't find any relevant clientId
|
|
||||||
throw new ForbiddenException(
|
|
||||||
String.format("User %s isn't associated with any registrar", userIdForLogging));
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns {@code true} if {@code user} is listed in contacts with access to the registrar.
|
|
||||||
*
|
|
||||||
* <p>Each registrar contact can either have getGaeUserId equals null or the user's gaeUserId.
|
|
||||||
* Null means the contact doesn't have access to the registrar console. None-null means the
|
|
||||||
* contact has access.
|
|
||||||
*/
|
|
||||||
private static boolean isInAllowedContacts(Registrar registrar, User user) {
|
|
||||||
String gaeUserId = user.getUserId();
|
|
||||||
return registrar
|
|
||||||
.getContacts()
|
|
||||||
.stream()
|
|
||||||
.anyMatch(contact -> gaeUserId.equals(contact.getGaeUserId()));
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -23,6 +23,8 @@
|
||||||
{template .main}
|
{template .main}
|
||||||
{@param xsrfToken: string} /** Security token. */
|
{@param xsrfToken: string} /** Security token. */
|
||||||
{@param clientId: string} /** Registrar client identifier. */
|
{@param clientId: string} /** Registrar client identifier. */
|
||||||
|
{@param readWriteClientIds: list<string>}
|
||||||
|
{@param readOnlyClientIds: list<string>}
|
||||||
{@param username: string} /** Arbitrary username to display. */
|
{@param username: string} /** Arbitrary username to display. */
|
||||||
{@param logoutUrl: string} /** Generated URL for logging out of Google. */
|
{@param logoutUrl: string} /** Generated URL for logging out of Google. */
|
||||||
{@param productName: string} /** Name to display for this software product. */
|
{@param productName: string} /** Name to display for this software product. */
|
||||||
|
@ -75,7 +77,33 @@
|
||||||
|
|
||||||
/** Sidebar nav. Ids on each elt for testing only. */
|
/** Sidebar nav. Ids on each elt for testing only. */
|
||||||
{template .navbar_ visibility="private"}
|
{template .navbar_ visibility="private"}
|
||||||
|
{@param clientId: string} /** Registrar client identifier. */
|
||||||
|
{@param readWriteClientIds: list<string>}
|
||||||
|
{@param readOnlyClientIds: list<string>}
|
||||||
|
|
||||||
<div id="reg-nav" class="{css('kd-content-sidebar')}">
|
<div id="reg-nav" class="{css('kd-content-sidebar')}">
|
||||||
|
<form>
|
||||||
|
<select name="clientId"
|
||||||
|
id="select-client-id"
|
||||||
|
class="{css('kd-button')} {css('kd-button-submit')}"
|
||||||
|
onchange='this.form.submit()'>
|
||||||
|
<option value="">[auto select]</option>
|
||||||
|
{if length($readWriteClientIds) > 0}
|
||||||
|
<optgroup label="READ/WRITE">
|
||||||
|
{for $id in $readWriteClientIds}
|
||||||
|
<option value="{$id}" {if $id == $clientId}selected{/if}>{$id}</option>
|
||||||
|
{/for}
|
||||||
|
</optgroup>
|
||||||
|
{/if}
|
||||||
|
{if length($readOnlyClientIds) > 0}
|
||||||
|
<optgroup label="READ ONLY">
|
||||||
|
{for $id in $readOnlyClientIds}
|
||||||
|
<option value="{$id}" {if $id == $clientId}selected{/if}>{$id}</option>
|
||||||
|
{/for}
|
||||||
|
</optgroup>
|
||||||
|
{/if}
|
||||||
|
</select>
|
||||||
|
</form>
|
||||||
<ul id="reg-navlist">
|
<ul id="reg-navlist">
|
||||||
<li>
|
<li>
|
||||||
<a href="#">Home</a>
|
<a href="#">Home</a>
|
||||||
|
@ -159,6 +187,12 @@
|
||||||
<a href="{$logoutUrl}"
|
<a href="{$logoutUrl}"
|
||||||
class="{css('kd-button')} {css('kd-button-submit')}"
|
class="{css('kd-button')} {css('kd-button-submit')}"
|
||||||
tabindex="-1">Logout and switch to another account</a>
|
tabindex="-1">Logout and switch to another account</a>
|
||||||
|
{if isNonnull($clientId)} // A clientId was given - but we don't have access to it
|
||||||
|
{sp}
|
||||||
|
<a href="?"
|
||||||
|
class="{css('kd-button')} {css('kd-button-submit')}"
|
||||||
|
tabindex="-1">Find registrar associated with your account</a>
|
||||||
|
{/if}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
{/template}
|
{/template}
|
||||||
|
|
|
@ -40,7 +40,7 @@ import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
import google.registry.ui.server.registrar.SessionUtils;
|
import google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.json.simple.JSONValue;
|
import org.json.simple.JSONValue;
|
||||||
|
@ -64,7 +64,8 @@ public class RdapActionBaseTest {
|
||||||
|
|
||||||
private final FakeResponse response = new FakeResponse();
|
private final FakeResponse response = new FakeResponse();
|
||||||
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
||||||
private final SessionUtils sessionUtils = mock(SessionUtils.class);
|
private final AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
|
mock(AuthenticatedRegistrarAccessor.class);
|
||||||
private final User user = new User("rdap.user@example.com", "gmail.com", "12345");
|
private final User user = new User("rdap.user@example.com", "gmail.com", "12345");
|
||||||
private final UserAuthInfo userAuthInfo = UserAuthInfo.create(user, false);
|
private final UserAuthInfo userAuthInfo = UserAuthInfo.create(user, false);
|
||||||
private final RdapMetrics rdapMetrics = mock(RdapMetrics.class);
|
private final RdapMetrics rdapMetrics = mock(RdapMetrics.class);
|
||||||
|
@ -119,7 +120,7 @@ public class RdapActionBaseTest {
|
||||||
createTld("thing");
|
createTld("thing");
|
||||||
inject.setStaticField(Ofy.class, "clock", clock);
|
inject.setStaticField(Ofy.class, "clock", clock);
|
||||||
action = new RdapTestAction();
|
action = new RdapTestAction();
|
||||||
action.sessionUtils = sessionUtils;
|
action.registrarAccessor = registrarAccessor;
|
||||||
action.authResult = AuthResult.create(AuthLevel.USER, userAuthInfo);
|
action.authResult = AuthResult.create(AuthLevel.USER, userAuthInfo);
|
||||||
action.includeDeletedParam = Optional.empty();
|
action.includeDeletedParam = Optional.empty();
|
||||||
action.registrarParam = Optional.empty();
|
action.registrarParam = Optional.empty();
|
||||||
|
|
|
@ -53,7 +53,7 @@ import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
import google.registry.ui.server.registrar.SessionUtils;
|
import google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
|
@ -82,7 +82,8 @@ public class RdapDomainActionTest {
|
||||||
|
|
||||||
private final FakeResponse response = new FakeResponse();
|
private final FakeResponse response = new FakeResponse();
|
||||||
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
||||||
private final SessionUtils sessionUtils = mock(SessionUtils.class);
|
private final AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
|
mock(AuthenticatedRegistrarAccessor.class);
|
||||||
private final RdapMetrics rdapMetrics = mock(RdapMetrics.class);
|
private final RdapMetrics rdapMetrics = mock(RdapMetrics.class);
|
||||||
|
|
||||||
private RdapDomainAction action;
|
private RdapDomainAction action;
|
||||||
|
@ -275,17 +276,17 @@ public class RdapDomainActionTest {
|
||||||
action.formatOutputParam = Optional.empty();
|
action.formatOutputParam = Optional.empty();
|
||||||
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
||||||
action.rdapWhoisServer = null;
|
action.rdapWhoisServer = null;
|
||||||
action.sessionUtils = sessionUtils;
|
action.registrarAccessor = registrarAccessor;
|
||||||
action.authResult = AUTH_RESULT;
|
action.authResult = AUTH_RESULT;
|
||||||
action.rdapMetrics = rdapMetrics;
|
action.rdapMetrics = rdapMetrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void login(String clientId) {
|
private void login(String clientId) {
|
||||||
when(sessionUtils.guessClientIdForUser(AUTH_RESULT)).thenReturn(clientId);
|
when(registrarAccessor.guessClientId()).thenReturn(clientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loginAsAdmin() {
|
private void loginAsAdmin() {
|
||||||
when(sessionUtils.guessClientIdForUser(AUTH_RESULT_ADMIN)).thenReturn("irrelevant");
|
when(registrarAccessor.guessClientId()).thenReturn("irrelevant");
|
||||||
action.authResult = AUTH_RESULT_ADMIN;
|
action.authResult = AUTH_RESULT_ADMIN;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -62,7 +62,7 @@ import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
import google.registry.ui.server.registrar.SessionUtils;
|
import google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor;
|
||||||
import google.registry.util.Idn;
|
import google.registry.util.Idn;
|
||||||
import java.net.IDN;
|
import java.net.IDN;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
|
@ -91,7 +91,8 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase {
|
||||||
@Rule public final InjectRule inject = new InjectRule();
|
@Rule public final InjectRule inject = new InjectRule();
|
||||||
|
|
||||||
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01T00:00:00Z"));
|
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01T00:00:00Z"));
|
||||||
private final SessionUtils sessionUtils = mock(SessionUtils.class);
|
private final AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
|
mock(AuthenticatedRegistrarAccessor.class);
|
||||||
private final RdapDomainSearchAction action = new RdapDomainSearchAction();
|
private final RdapDomainSearchAction action = new RdapDomainSearchAction();
|
||||||
|
|
||||||
private static final AuthResult AUTH_RESULT =
|
private static final AuthResult AUTH_RESULT =
|
||||||
|
@ -405,7 +406,7 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase {
|
||||||
action.formatOutputParam = Optional.empty();
|
action.formatOutputParam = Optional.empty();
|
||||||
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
||||||
action.rdapWhoisServer = null;
|
action.rdapWhoisServer = null;
|
||||||
action.sessionUtils = sessionUtils;
|
action.registrarAccessor = registrarAccessor;
|
||||||
action.authResult = AUTH_RESULT;
|
action.authResult = AUTH_RESULT;
|
||||||
action.rdapMetrics = rdapMetrics;
|
action.rdapMetrics = rdapMetrics;
|
||||||
action.cursorTokenParam = Optional.empty();
|
action.cursorTokenParam = Optional.empty();
|
||||||
|
@ -413,12 +414,12 @@ public class RdapDomainSearchActionTest extends RdapSearchActionTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private void login(String clientId) {
|
private void login(String clientId) {
|
||||||
when(sessionUtils.guessClientIdForUser(AUTH_RESULT)).thenReturn(clientId);
|
when(registrarAccessor.guessClientId()).thenReturn(clientId);
|
||||||
metricRole = REGISTRAR;
|
metricRole = REGISTRAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loginAsAdmin() {
|
private void loginAsAdmin() {
|
||||||
when(sessionUtils.guessClientIdForUser(AUTH_RESULT)).thenReturn("irrelevant");
|
when(registrarAccessor.guessClientId()).thenReturn("irrelevant");
|
||||||
action.authResult = AUTH_RESULT_ADMIN;
|
action.authResult = AUTH_RESULT_ADMIN;
|
||||||
metricRole = ADMINISTRATOR;
|
metricRole = ADMINISTRATOR;
|
||||||
}
|
}
|
||||||
|
|
|
@ -49,7 +49,7 @@ import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
import google.registry.ui.server.registrar.SessionUtils;
|
import google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -75,7 +75,8 @@ public class RdapEntityActionTest {
|
||||||
|
|
||||||
private final FakeResponse response = new FakeResponse();
|
private final FakeResponse response = new FakeResponse();
|
||||||
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
||||||
private final SessionUtils sessionUtils = mock(SessionUtils.class);
|
private final AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
|
mock(AuthenticatedRegistrarAccessor.class);
|
||||||
private final RdapMetrics rdapMetrics = mock(RdapMetrics.class);
|
private final RdapMetrics rdapMetrics = mock(RdapMetrics.class);
|
||||||
|
|
||||||
private RdapEntityAction action;
|
private RdapEntityAction action;
|
||||||
|
@ -176,18 +177,18 @@ public class RdapEntityActionTest {
|
||||||
action.formatOutputParam = Optional.empty();
|
action.formatOutputParam = Optional.empty();
|
||||||
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
||||||
action.rdapWhoisServer = null;
|
action.rdapWhoisServer = null;
|
||||||
action.sessionUtils = sessionUtils;
|
action.registrarAccessor = registrarAccessor;
|
||||||
action.authResult = AUTH_RESULT;
|
action.authResult = AUTH_RESULT;
|
||||||
action.rdapMetrics = rdapMetrics;
|
action.rdapMetrics = rdapMetrics;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void login(String registrar) {
|
private void login(String registrar) {
|
||||||
when(sessionUtils.guessClientIdForUser(AUTH_RESULT)).thenReturn(registrar);
|
when(registrarAccessor.guessClientId()).thenReturn(registrar);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loginAsAdmin() {
|
private void loginAsAdmin() {
|
||||||
action.authResult = AUTH_RESULT_ADMIN;
|
action.authResult = AUTH_RESULT_ADMIN;
|
||||||
when(sessionUtils.guessClientIdForUser(AUTH_RESULT_ADMIN)).thenReturn("irrelevant");
|
when(registrarAccessor.guessClientId()).thenReturn("irrelevant");
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object generateActualJson(String name) {
|
private Object generateActualJson(String name) {
|
||||||
|
|
|
@ -53,7 +53,7 @@ import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
import google.registry.ui.server.registrar.SessionUtils;
|
import google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
@ -82,7 +82,8 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase {
|
||||||
}
|
}
|
||||||
|
|
||||||
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01T00:00:00Z"));
|
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01T00:00:00Z"));
|
||||||
private final SessionUtils sessionUtils = mock(SessionUtils.class);
|
private final AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
|
mock(AuthenticatedRegistrarAccessor.class);
|
||||||
private final RdapEntitySearchAction action = new RdapEntitySearchAction();
|
private final RdapEntitySearchAction action = new RdapEntitySearchAction();
|
||||||
|
|
||||||
private FakeResponse response = new FakeResponse();
|
private FakeResponse response = new FakeResponse();
|
||||||
|
@ -202,20 +203,20 @@ public class RdapEntitySearchActionTest extends RdapSearchActionTestCase {
|
||||||
action.registrarParam = Optional.empty();
|
action.registrarParam = Optional.empty();
|
||||||
action.includeDeletedParam = Optional.empty();
|
action.includeDeletedParam = Optional.empty();
|
||||||
action.formatOutputParam = Optional.empty();
|
action.formatOutputParam = Optional.empty();
|
||||||
action.sessionUtils = sessionUtils;
|
action.registrarAccessor = registrarAccessor;
|
||||||
action.authResult = AUTH_RESULT;
|
action.authResult = AUTH_RESULT;
|
||||||
action.rdapMetrics = rdapMetrics;
|
action.rdapMetrics = rdapMetrics;
|
||||||
action.cursorTokenParam = Optional.empty();
|
action.cursorTokenParam = Optional.empty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void login(String registrar) {
|
private void login(String registrar) {
|
||||||
when(sessionUtils.guessClientIdForUser(AUTH_RESULT)).thenReturn(registrar);
|
when(registrarAccessor.guessClientId()).thenReturn(registrar);
|
||||||
metricRole = REGISTRAR;
|
metricRole = REGISTRAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loginAsAdmin() {
|
private void loginAsAdmin() {
|
||||||
action.authResult = AUTH_RESULT_ADMIN;
|
action.authResult = AUTH_RESULT_ADMIN;
|
||||||
when(sessionUtils.guessClientIdForUser(AUTH_RESULT_ADMIN)).thenReturn("irrelevant");
|
when(registrarAccessor.guessClientId()).thenReturn("irrelevant");
|
||||||
metricRole = ADMINISTRATOR;
|
metricRole = ADMINISTRATOR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -33,7 +33,7 @@ import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
import google.registry.ui.server.registrar.SessionUtils;
|
import google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.json.simple.JSONValue;
|
import org.json.simple.JSONValue;
|
||||||
|
@ -52,7 +52,8 @@ public class RdapHelpActionTest {
|
||||||
|
|
||||||
private final FakeResponse response = new FakeResponse();
|
private final FakeResponse response = new FakeResponse();
|
||||||
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
||||||
private final SessionUtils sessionUtils = mock(SessionUtils.class);
|
private final AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
|
mock(AuthenticatedRegistrarAccessor.class);
|
||||||
private final User user = new User("rdap.user@example.com", "gmail.com", "12345");
|
private final User user = new User("rdap.user@example.com", "gmail.com", "12345");
|
||||||
private final UserAuthInfo userAuthInfo = UserAuthInfo.create(user, false);
|
private final UserAuthInfo userAuthInfo = UserAuthInfo.create(user, false);
|
||||||
private final RdapMetrics rdapMetrics = mock(RdapMetrics.class);
|
private final RdapMetrics rdapMetrics = mock(RdapMetrics.class);
|
||||||
|
@ -67,7 +68,7 @@ public class RdapHelpActionTest {
|
||||||
action.clock = clock;
|
action.clock = clock;
|
||||||
action.fullServletPath = "https://example.tld/rdap";
|
action.fullServletPath = "https://example.tld/rdap";
|
||||||
action.requestMethod = Action.Method.GET;
|
action.requestMethod = Action.Method.GET;
|
||||||
action.sessionUtils = sessionUtils;
|
action.registrarAccessor = registrarAccessor;
|
||||||
action.authResult = AuthResult.create(AuthLevel.USER, userAuthInfo);
|
action.authResult = AuthResult.create(AuthLevel.USER, userAuthInfo);
|
||||||
action.includeDeletedParam = Optional.empty();
|
action.includeDeletedParam = Optional.empty();
|
||||||
action.registrarParam = Optional.empty();
|
action.registrarParam = Optional.empty();
|
||||||
|
|
|
@ -43,7 +43,7 @@ import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
import google.registry.ui.server.registrar.SessionUtils;
|
import google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -69,7 +69,8 @@ public class RdapNameserverActionTest {
|
||||||
|
|
||||||
private final FakeResponse response = new FakeResponse();
|
private final FakeResponse response = new FakeResponse();
|
||||||
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01TZ"));
|
||||||
private final SessionUtils sessionUtils = mock(SessionUtils.class);
|
private final AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
|
mock(AuthenticatedRegistrarAccessor.class);
|
||||||
private final RdapMetrics rdapMetrics = mock(RdapMetrics.class);
|
private final RdapMetrics rdapMetrics = mock(RdapMetrics.class);
|
||||||
|
|
||||||
private static final AuthResult AUTH_RESULT =
|
private static final AuthResult AUTH_RESULT =
|
||||||
|
@ -132,7 +133,7 @@ public class RdapNameserverActionTest {
|
||||||
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
||||||
action.rdapWhoisServer = null;
|
action.rdapWhoisServer = null;
|
||||||
action.authResult = authResult;
|
action.authResult = authResult;
|
||||||
action.sessionUtils = sessionUtils;
|
action.registrarAccessor = registrarAccessor;
|
||||||
action.rdapMetrics = rdapMetrics;
|
action.rdapMetrics = rdapMetrics;
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
@ -362,21 +363,21 @@ public class RdapNameserverActionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeletedNameserver_notFound_notLoggedIn() {
|
public void testDeletedNameserver_notFound_notLoggedIn() {
|
||||||
when(sessionUtils.guessClientIdForUser(AUTH_RESULT)).thenThrow(new ForbiddenException("blah"));
|
when(registrarAccessor.guessClientId()).thenThrow(new ForbiddenException("blah"));
|
||||||
generateActualJson("nsdeleted.cat.lol", Optional.empty(), Optional.of(true));
|
generateActualJson("nsdeleted.cat.lol", Optional.empty(), Optional.of(true));
|
||||||
assertThat(response.getStatus()).isEqualTo(404);
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeletedNameserver_notFound_loggedInAsDifferentRegistrar() {
|
public void testDeletedNameserver_notFound_loggedInAsDifferentRegistrar() {
|
||||||
when(sessionUtils.guessClientIdForUser(AUTH_RESULT)).thenReturn("otherregistrar");
|
when(registrarAccessor.guessClientId()).thenReturn("otherregistrar");
|
||||||
generateActualJson("nsdeleted.cat.lol", Optional.empty(), Optional.of(true));
|
generateActualJson("nsdeleted.cat.lol", Optional.empty(), Optional.of(true));
|
||||||
assertThat(response.getStatus()).isEqualTo(404);
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeletedNameserver_found_loggedInAsCorrectRegistrar() {
|
public void testDeletedNameserver_found_loggedInAsCorrectRegistrar() {
|
||||||
when(sessionUtils.guessClientIdForUser(AUTH_RESULT)).thenReturn("TheRegistrar");
|
when(registrarAccessor.guessClientId()).thenReturn("TheRegistrar");
|
||||||
assertThat(
|
assertThat(
|
||||||
generateActualJson("nsdeleted.cat.lol", Optional.empty(), Optional.of(true)))
|
generateActualJson("nsdeleted.cat.lol", Optional.empty(), Optional.of(true)))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
|
@ -393,7 +394,7 @@ public class RdapNameserverActionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeletedNameserver_found_loggedInAsAdmin() {
|
public void testDeletedNameserver_found_loggedInAsAdmin() {
|
||||||
when(sessionUtils.guessClientIdForUser(AUTH_RESULT_ADMIN)).thenReturn("irrelevant");
|
when(registrarAccessor.guessClientId()).thenReturn("irrelevant");
|
||||||
newRdapNameserverAction(
|
newRdapNameserverAction(
|
||||||
"nsdeleted.cat.lol",
|
"nsdeleted.cat.lol",
|
||||||
Optional.empty(),
|
Optional.empty(),
|
||||||
|
@ -415,7 +416,7 @@ public class RdapNameserverActionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeletedNameserver_found_sameRegistrarRequested() {
|
public void testDeletedNameserver_found_sameRegistrarRequested() {
|
||||||
when(sessionUtils.guessClientIdForUser(AUTH_RESULT)).thenReturn("TheRegistrar");
|
when(registrarAccessor.guessClientId()).thenReturn("TheRegistrar");
|
||||||
assertThat(
|
assertThat(
|
||||||
generateActualJson("nsdeleted.cat.lol", Optional.of("TheRegistrar"), Optional.of(true)))
|
generateActualJson("nsdeleted.cat.lol", Optional.of("TheRegistrar"), Optional.of(true)))
|
||||||
.isEqualTo(
|
.isEqualTo(
|
||||||
|
@ -432,7 +433,7 @@ public class RdapNameserverActionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testDeletedNameserver_notFound_differentRegistrarRequested() {
|
public void testDeletedNameserver_notFound_differentRegistrarRequested() {
|
||||||
when(sessionUtils.guessClientIdForUser(AUTH_RESULT)).thenReturn("TheRegistrar");
|
when(registrarAccessor.guessClientId()).thenReturn("TheRegistrar");
|
||||||
generateActualJson("ns1.cat.lol", Optional.of("otherregistrar"), Optional.of(false));
|
generateActualJson("ns1.cat.lol", Optional.of("otherregistrar"), Optional.of(false));
|
||||||
assertThat(response.getStatus()).isEqualTo(404);
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
}
|
}
|
||||||
|
|
|
@ -54,7 +54,7 @@ import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
import google.registry.ui.server.registrar.SessionUtils;
|
import google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor;
|
||||||
import java.net.URLDecoder;
|
import java.net.URLDecoder;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
@ -78,7 +78,8 @@ public class RdapNameserverSearchActionTest extends RdapSearchActionTestCase {
|
||||||
|
|
||||||
private FakeResponse response = new FakeResponse();
|
private FakeResponse response = new FakeResponse();
|
||||||
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01T00:00:00Z"));
|
private final FakeClock clock = new FakeClock(DateTime.parse("2000-01-01T00:00:00Z"));
|
||||||
private final SessionUtils sessionUtils = mock(SessionUtils.class);
|
private final AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
|
mock(AuthenticatedRegistrarAccessor.class);
|
||||||
private final RdapNameserverSearchAction action = new RdapNameserverSearchAction();
|
private final RdapNameserverSearchAction action = new RdapNameserverSearchAction();
|
||||||
|
|
||||||
private static final AuthResult AUTH_RESULT =
|
private static final AuthResult AUTH_RESULT =
|
||||||
|
@ -200,17 +201,17 @@ public class RdapNameserverSearchActionTest extends RdapSearchActionTestCase {
|
||||||
action.includeDeletedParam = Optional.empty();
|
action.includeDeletedParam = Optional.empty();
|
||||||
action.formatOutputParam = Optional.empty();
|
action.formatOutputParam = Optional.empty();
|
||||||
action.authResult = AUTH_RESULT;
|
action.authResult = AUTH_RESULT;
|
||||||
action.sessionUtils = sessionUtils;
|
action.registrarAccessor = registrarAccessor;
|
||||||
action.rdapMetrics = rdapMetrics;
|
action.rdapMetrics = rdapMetrics;
|
||||||
action.cursorTokenParam = Optional.empty();
|
action.cursorTokenParam = Optional.empty();
|
||||||
}
|
}
|
||||||
private void login(String clientId) {
|
private void login(String clientId) {
|
||||||
when(sessionUtils.guessClientIdForUser(AUTH_RESULT)).thenReturn(clientId);
|
when(registrarAccessor.guessClientId()).thenReturn(clientId);
|
||||||
metricRole = REGISTRAR;
|
metricRole = REGISTRAR;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void loginAsAdmin() {
|
private void loginAsAdmin() {
|
||||||
when(sessionUtils.guessClientIdForUser(AUTH_RESULT_ADMIN)).thenReturn("irrelevant");
|
when(registrarAccessor.guessClientId()).thenReturn("irrelevant");
|
||||||
action.authResult = AUTH_RESULT_ADMIN;
|
action.authResult = AUTH_RESULT_ADMIN;
|
||||||
metricRole = ADMINISTRATOR;
|
metricRole = ADMINISTRATOR;
|
||||||
}
|
}
|
||||||
|
|
|
@ -62,6 +62,8 @@ registry.registrar.ConsoleTestUtil.renderConsoleMain = function(
|
||||||
logoutUrl: args.logoutUrl || 'https://logout.url.com',
|
logoutUrl: args.logoutUrl || 'https://logout.url.com',
|
||||||
isAdmin: goog.isDefAndNotNull(args.isAdmin) ? args.isAdmin : true,
|
isAdmin: goog.isDefAndNotNull(args.isAdmin) ? args.isAdmin : true,
|
||||||
clientId: args.clientId || 'ignore',
|
clientId: args.clientId || 'ignore',
|
||||||
|
readWriteClientIds: args.readWriteClientIds || ['readWrite'],
|
||||||
|
readOnlyClientIds: args.readOnlyClientIds || ['readOnly'],
|
||||||
logoFilename: args.logoFilename || 'logo.png',
|
logoFilename: args.logoFilename || 'logo.png',
|
||||||
productName: args.productName || 'Nomulus',
|
productName: args.productName || 'Nomulus',
|
||||||
integrationEmail: args.integrationEmail || 'integration@example.com',
|
integrationEmail: args.integrationEmail || 'integration@example.com',
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
// Copyright 2017 The Nomulus Authors. All Rights Reserved.
|
// Copyright 2018 The Nomulus Authors. All Rights Reserved.
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
|
@ -20,8 +20,8 @@ import static google.registry.testing.DatastoreHelper.loadRegistrar;
|
||||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||||
import static google.registry.testing.JUnitBackports.assertThrows;
|
import static google.registry.testing.JUnitBackports.assertThrows;
|
||||||
import static google.registry.testing.LogsSubject.assertAboutLogs;
|
import static google.registry.testing.LogsSubject.assertAboutLogs;
|
||||||
import static google.registry.ui.server.registrar.SessionUtils.AccessType.READ_ONLY;
|
import static google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor.AccessType.READ;
|
||||||
import static google.registry.ui.server.registrar.SessionUtils.AccessType.READ_WRITE;
|
import static google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor.AccessType.UPDATE;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
import com.google.appengine.api.users.User;
|
import com.google.appengine.api.users.User;
|
||||||
|
@ -34,7 +34,7 @@ import google.registry.request.auth.AuthResult;
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
import google.registry.testing.AppEngineRule;
|
import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
import google.registry.ui.server.registrar.SessionUtils.AccessType;
|
import google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor.AccessType;
|
||||||
import java.util.logging.Level;
|
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;
|
||||||
|
@ -45,9 +45,9 @@ import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
import org.junit.runners.JUnit4;
|
import org.junit.runners.JUnit4;
|
||||||
|
|
||||||
/** Unit tests for {@link SessionUtils}. */
|
/** Unit tests for {@link AuthenticatedRegistrarAccessor}. */
|
||||||
@RunWith(JUnit4.class)
|
@RunWith(JUnit4.class)
|
||||||
public class SessionUtilsTest {
|
public class AuthenticatedRegistrarAccessorTest {
|
||||||
|
|
||||||
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
@Rule public final AppEngineRule appEngine = AppEngineRule.builder().withDatastore().build();
|
||||||
@Rule public final InjectRule inject = new InjectRule();
|
@Rule public final InjectRule inject = new InjectRule();
|
||||||
|
@ -56,8 +56,6 @@ public class SessionUtilsTest {
|
||||||
private final HttpServletResponse rsp = mock(HttpServletResponse.class);
|
private final HttpServletResponse rsp = mock(HttpServletResponse.class);
|
||||||
private final TestLogHandler testLogHandler = new TestLogHandler();
|
private final TestLogHandler testLogHandler = new TestLogHandler();
|
||||||
|
|
||||||
private SessionUtils sessionUtils;
|
|
||||||
|
|
||||||
private static final AuthResult AUTHORIZED_USER = createAuthResult(true, false);
|
private static final AuthResult AUTHORIZED_USER = createAuthResult(true, false);
|
||||||
private static final AuthResult UNAUTHORIZED_USER = createAuthResult(false, false);
|
private static final AuthResult UNAUTHORIZED_USER = createAuthResult(false, false);
|
||||||
private static final AuthResult AUTHORIZED_ADMIN = createAuthResult(true, true);
|
private static final AuthResult AUTHORIZED_ADMIN = createAuthResult(true, true);
|
||||||
|
@ -80,15 +78,13 @@ public class SessionUtilsTest {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void before() {
|
public void before() {
|
||||||
LoggerConfig.getConfig(SessionUtils.class).addHandler(testLogHandler);
|
LoggerConfig.getConfig(AuthenticatedRegistrarAccessor.class).addHandler(testLogHandler);
|
||||||
sessionUtils = new SessionUtils();
|
|
||||||
sessionUtils.registryAdminClientId = ADMIN_CLIENT_ID;
|
|
||||||
persistResource(loadRegistrar(ADMIN_CLIENT_ID));
|
persistResource(loadRegistrar(ADMIN_CLIENT_ID));
|
||||||
}
|
}
|
||||||
|
|
||||||
@After
|
@After
|
||||||
public void after() {
|
public void after() {
|
||||||
LoggerConfig.getConfig(SessionUtils.class).removeHandler(testLogHandler);
|
LoggerConfig.getConfig(AuthenticatedRegistrarAccessor.class).removeHandler(testLogHandler);
|
||||||
}
|
}
|
||||||
|
|
||||||
private String formatMessage(String message, AuthResult authResult, String clientId) {
|
private String formatMessage(String message, AuthResult authResult, String clientId) {
|
||||||
|
@ -97,14 +93,78 @@ public class SessionUtilsTest {
|
||||||
.replace("{clientId}", String.valueOf(clientId));
|
.replace("{clientId}", String.valueOf(clientId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Users only have access to the registrars they are a contact for. */
|
||||||
|
@Test
|
||||||
|
public void getAllClientIdWithAccess_authorizedUser() {
|
||||||
|
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
|
new AuthenticatedRegistrarAccessor(AUTHORIZED_USER, ADMIN_CLIENT_ID);
|
||||||
|
|
||||||
|
assertThat(registrarAccessor.getAllClientIdWithAccess())
|
||||||
|
.containsExactly(
|
||||||
|
UPDATE, DEFAULT_CLIENT_ID,
|
||||||
|
READ, DEFAULT_CLIENT_ID)
|
||||||
|
.inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Logged out users don't have access to anything. */
|
||||||
|
@Test
|
||||||
|
public void getAllClientIdWithAccess_loggedOutUser() {
|
||||||
|
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
|
new AuthenticatedRegistrarAccessor(NO_USER, ADMIN_CLIENT_ID);
|
||||||
|
|
||||||
|
ForbiddenException exception =
|
||||||
|
assertThrows(ForbiddenException.class, () -> registrarAccessor.getAllClientIdWithAccess());
|
||||||
|
assertThat(exception).hasMessageThat().contains("Not logged in");
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Unauthorized users don't have access to anything. */
|
||||||
|
@Test
|
||||||
|
public void getAllClientIdWithAccess_unauthorizedUser() {
|
||||||
|
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
|
new AuthenticatedRegistrarAccessor(UNAUTHORIZED_USER, ADMIN_CLIENT_ID);
|
||||||
|
|
||||||
|
assertThat(registrarAccessor.getAllClientIdWithAccess()).isEmpty();
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Admins have read/write access to the authorized registrars, AND the admin registrar. */
|
||||||
|
@Test
|
||||||
|
public void getAllClientIdWithAccess_authorizedAdmin() {
|
||||||
|
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
|
new AuthenticatedRegistrarAccessor(AUTHORIZED_ADMIN, ADMIN_CLIENT_ID);
|
||||||
|
|
||||||
|
assertThat(registrarAccessor.getAllClientIdWithAccess())
|
||||||
|
.containsExactly(
|
||||||
|
UPDATE, DEFAULT_CLIENT_ID,
|
||||||
|
READ, DEFAULT_CLIENT_ID,
|
||||||
|
UPDATE, ADMIN_CLIENT_ID,
|
||||||
|
READ, ADMIN_CLIENT_ID)
|
||||||
|
.inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Unauthorized admins only have full access to the admin registrar, and read-only to the rest.
|
||||||
|
*/
|
||||||
|
@Test
|
||||||
|
public void getAllClientIdWithAccess_unauthorizedAdmin() {
|
||||||
|
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
|
new AuthenticatedRegistrarAccessor(UNAUTHORIZED_ADMIN, ADMIN_CLIENT_ID);
|
||||||
|
|
||||||
|
assertThat(registrarAccessor.getAllClientIdWithAccess())
|
||||||
|
.containsExactly(
|
||||||
|
UPDATE, ADMIN_CLIENT_ID,
|
||||||
|
READ, ADMIN_CLIENT_ID,
|
||||||
|
READ, DEFAULT_CLIENT_ID)
|
||||||
|
.inOrder();
|
||||||
|
}
|
||||||
|
|
||||||
/** Fail loading registrar if user doesn't have access to it. */
|
/** Fail loading registrar if user doesn't have access to it. */
|
||||||
@Test
|
@Test
|
||||||
public void testGetRegistrarForUser_readOnly_noAccess_isNotAdmin() {
|
public void testGetRegistrarForUser_readOnly_noAccess_isNotAdmin() {
|
||||||
expectGetRegistrarFailure(
|
expectGetRegistrarFailure(
|
||||||
DEFAULT_CLIENT_ID,
|
DEFAULT_CLIENT_ID,
|
||||||
READ_ONLY,
|
READ,
|
||||||
UNAUTHORIZED_USER,
|
UNAUTHORIZED_USER,
|
||||||
"User {user} doesn't have READ_ONLY access to registrar {clientId}");
|
"User {user} doesn't have READ access to registrar {clientId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fail loading registrar if user doesn't have access to it. */
|
/** Fail loading registrar if user doesn't have access to it. */
|
||||||
|
@ -112,60 +172,56 @@ public class SessionUtilsTest {
|
||||||
public void testGetRegistrarForUser_readWrite_noAccess_isNotAdmin() {
|
public void testGetRegistrarForUser_readWrite_noAccess_isNotAdmin() {
|
||||||
expectGetRegistrarFailure(
|
expectGetRegistrarFailure(
|
||||||
DEFAULT_CLIENT_ID,
|
DEFAULT_CLIENT_ID,
|
||||||
READ_WRITE,
|
UPDATE,
|
||||||
UNAUTHORIZED_USER,
|
UNAUTHORIZED_USER,
|
||||||
"User {user} doesn't have READ_WRITE access to registrar {clientId}");
|
"User {user} doesn't have UPDATE access to registrar {clientId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fail loading registrar if there's no user associated with the request. */
|
/** Fail loading registrar if there's no user associated with the request. */
|
||||||
@Test
|
@Test
|
||||||
public void testGetRegistrarForUser_readOnly_noUser() {
|
public void testGetRegistrarForUser_readOnly_noUser() {
|
||||||
expectGetRegistrarFailure(DEFAULT_CLIENT_ID, READ_ONLY, NO_USER, "Not logged in");
|
expectGetRegistrarFailure(DEFAULT_CLIENT_ID, READ, NO_USER, "Not logged in");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fail loading registrar if there's no user associated with the request. */
|
/** Fail loading registrar if there's no user associated with the request. */
|
||||||
@Test
|
@Test
|
||||||
public void testGetRegistrarForUser_readWrite_noUser() {
|
public void testGetRegistrarForUser_readWrite_noUser() {
|
||||||
expectGetRegistrarFailure(DEFAULT_CLIENT_ID, READ_WRITE, NO_USER, "Not logged in");
|
expectGetRegistrarFailure(DEFAULT_CLIENT_ID, UPDATE, NO_USER, "Not logged in");
|
||||||
|
|
||||||
assertAboutLogs().that(testLogHandler).hasNoLogsAtLevel(Level.INFO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Succeed loading registrar in read-only mode if user has access to it. */
|
/** Succeed loading registrar in read-only mode if user has access to it. */
|
||||||
@Test
|
@Test
|
||||||
public void testGetRegistrarForUser_readOnly_hasAccess_isNotAdmin() {
|
public void testGetRegistrarForUser_readOnly_hasAccess_isNotAdmin() {
|
||||||
expectGetRegistrarSuccess(
|
expectGetRegistrarSuccess(
|
||||||
AUTHORIZED_USER, READ_ONLY, "User {user} has access to registrar {clientId}");
|
AUTHORIZED_USER, READ, "User {user} has READ access to registrar {clientId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Succeed loading registrar in read-write mode if user has access to it. */
|
/** Succeed loading registrar in read-write mode if user has access to it. */
|
||||||
@Test
|
@Test
|
||||||
public void testGetRegistrarForUser_readWrite_hasAccess_isNotAdmin() {
|
public void testGetRegistrarForUser_readWrite_hasAccess_isNotAdmin() {
|
||||||
expectGetRegistrarSuccess(
|
expectGetRegistrarSuccess(
|
||||||
AUTHORIZED_USER, READ_WRITE, "User {user} has access to registrar {clientId}");
|
AUTHORIZED_USER, UPDATE, "User {user} has UPDATE access to registrar {clientId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Succeed loading registrar in read-only mode if admin with access. */
|
/** Succeed loading registrar in read-only mode if admin with access. */
|
||||||
@Test
|
@Test
|
||||||
public void testGetRegistrarForUser_readOnly_hasAccess_isAdmin() {
|
public void testGetRegistrarForUser_readOnly_hasAccess_isAdmin() {
|
||||||
expectGetRegistrarSuccess(
|
expectGetRegistrarSuccess(
|
||||||
AUTHORIZED_ADMIN, READ_ONLY, "User {user} has access to registrar {clientId}");
|
AUTHORIZED_ADMIN, READ, "User {user} has READ access to registrar {clientId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Succeed loading registrar in read-write mode if admin with access. */
|
/** Succeed loading registrar in read-write mode if admin with access. */
|
||||||
@Test
|
@Test
|
||||||
public void testGetRegistrarForUser_readWrite_hasAccess_isAdmin() {
|
public void testGetRegistrarForUser_readWrite_hasAccess_isAdmin() {
|
||||||
expectGetRegistrarSuccess(
|
expectGetRegistrarSuccess(
|
||||||
AUTHORIZED_ADMIN, READ_WRITE, "User {user} has access to registrar {clientId}");
|
AUTHORIZED_ADMIN, UPDATE, "User {user} has UPDATE access to registrar {clientId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Succeed loading registrar for read-only when admin isn't on the approved contacts list. */
|
/** Succeed loading registrar for read-only when admin isn't on the approved contacts list. */
|
||||||
@Test
|
@Test
|
||||||
public void testGetRegistrarForUser_readOnly_noAccess_isAdmin() {
|
public void testGetRegistrarForUser_readOnly_noAccess_isAdmin() {
|
||||||
expectGetRegistrarSuccess(
|
expectGetRegistrarSuccess(
|
||||||
UNAUTHORIZED_ADMIN,
|
UNAUTHORIZED_ADMIN, READ, "User {user} has READ access to registrar {clientId}.");
|
||||||
READ_ONLY,
|
|
||||||
"Allowing admin {user} read-only access to registrar {clientId}.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fail loading registrar for read-write when admin isn't on the approved contacts list. */
|
/** Fail loading registrar for read-write when admin isn't on the approved contacts list. */
|
||||||
|
@ -173,9 +229,9 @@ public class SessionUtilsTest {
|
||||||
public void testGetRegistrarForUser_readWrite_noAccess_isAdmin() {
|
public void testGetRegistrarForUser_readWrite_noAccess_isAdmin() {
|
||||||
expectGetRegistrarFailure(
|
expectGetRegistrarFailure(
|
||||||
DEFAULT_CLIENT_ID,
|
DEFAULT_CLIENT_ID,
|
||||||
READ_WRITE,
|
UPDATE,
|
||||||
UNAUTHORIZED_ADMIN,
|
UNAUTHORIZED_ADMIN,
|
||||||
"User {user} doesn't have READ_WRITE access to registrar {clientId}");
|
"User {user} doesn't have UPDATE access to registrar {clientId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fail loading registrar even if admin, if registrar doesn't exist. */
|
/** Fail loading registrar even if admin, if registrar doesn't exist. */
|
||||||
|
@ -183,9 +239,9 @@ public class SessionUtilsTest {
|
||||||
public void testGetRegistrarForUser_readOnly_doesntExist_isAdmin() {
|
public void testGetRegistrarForUser_readOnly_doesntExist_isAdmin() {
|
||||||
expectGetRegistrarFailure(
|
expectGetRegistrarFailure(
|
||||||
"BadClientId",
|
"BadClientId",
|
||||||
READ_ONLY,
|
READ,
|
||||||
AUTHORIZED_ADMIN,
|
AUTHORIZED_ADMIN,
|
||||||
"Registrar {clientId} not found");
|
"User {user} doesn't have READ access to registrar {clientId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Fail loading registrar even if admin, if registrar doesn't exist. */
|
/** Fail loading registrar even if admin, if registrar doesn't exist. */
|
||||||
|
@ -193,15 +249,17 @@ public class SessionUtilsTest {
|
||||||
public void testGetRegistrarForUser_readWrite_doesntExist_isAdmin() {
|
public void testGetRegistrarForUser_readWrite_doesntExist_isAdmin() {
|
||||||
expectGetRegistrarFailure(
|
expectGetRegistrarFailure(
|
||||||
"BadClientId",
|
"BadClientId",
|
||||||
READ_WRITE,
|
UPDATE,
|
||||||
AUTHORIZED_ADMIN,
|
AUTHORIZED_ADMIN,
|
||||||
"Registrar {clientId} not found");
|
"User {user} doesn't have UPDATE access to registrar {clientId}");
|
||||||
}
|
}
|
||||||
|
|
||||||
private void expectGetRegistrarSuccess(
|
private void expectGetRegistrarSuccess(
|
||||||
AuthResult authResult, AccessType accessType, String message) {
|
AuthResult authResult, AccessType accessType, String message) {
|
||||||
assertThat(sessionUtils.getRegistrarForUser(DEFAULT_CLIENT_ID, accessType, authResult))
|
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
.isNotNull();
|
new AuthenticatedRegistrarAccessor(authResult, ADMIN_CLIENT_ID);
|
||||||
|
|
||||||
|
assertThat(registrarAccessor.getRegistrar(DEFAULT_CLIENT_ID, accessType)).isNotNull();
|
||||||
assertAboutLogs()
|
assertAboutLogs()
|
||||||
.that(testLogHandler)
|
.that(testLogHandler)
|
||||||
.hasLogAtLevelWithMessage(
|
.hasLogAtLevelWithMessage(
|
||||||
|
@ -210,22 +268,23 @@ public class SessionUtilsTest {
|
||||||
|
|
||||||
private void expectGetRegistrarFailure(
|
private void expectGetRegistrarFailure(
|
||||||
String clientId, AccessType accessType, AuthResult authResult, String message) {
|
String clientId, AccessType accessType, AuthResult authResult, String message) {
|
||||||
|
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
|
new AuthenticatedRegistrarAccessor(authResult, ADMIN_CLIENT_ID);
|
||||||
|
|
||||||
ForbiddenException exception =
|
ForbiddenException exception =
|
||||||
assertThrows(
|
assertThrows(
|
||||||
ForbiddenException.class,
|
ForbiddenException.class, () -> registrarAccessor.getRegistrar(clientId, accessType));
|
||||||
() -> sessionUtils.getRegistrarForUser(clientId, accessType, authResult));
|
|
||||||
|
|
||||||
assertThat(exception).hasMessageThat().contains(formatMessage(message, authResult, clientId));
|
assertThat(exception).hasMessageThat().contains(formatMessage(message, authResult, clientId));
|
||||||
assertAboutLogs().that(testLogHandler).hasNoLogsAtLevel(Level.INFO);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** If a user has access to a registrar, we should guess that registrar. */
|
/** If a user has access to a registrar, we should guess that registrar. */
|
||||||
@Test
|
@Test
|
||||||
public void testGuessClientIdForUser_hasAccess_isNotAdmin() {
|
public void testGuessClientIdForUser_hasAccess_isNotAdmin() {
|
||||||
expectGuessRegistrarSuccess(
|
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
AUTHORIZED_USER,
|
new AuthenticatedRegistrarAccessor(AUTHORIZED_USER, ADMIN_CLIENT_ID);
|
||||||
DEFAULT_CLIENT_ID,
|
|
||||||
"Associating user {user} with found registrar {clientId}.");
|
assertThat(registrarAccessor.guessClientId()).isEqualTo(DEFAULT_CLIENT_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** If a user doesn't have access to any registrars, guess returns nothing. */
|
/** If a user doesn't have access to any registrars, guess returns nothing. */
|
||||||
|
@ -241,40 +300,32 @@ public class SessionUtilsTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGuessClientIdForUser_hasAccess_isAdmin() {
|
public void testGuessClientIdForUser_hasAccess_isAdmin() {
|
||||||
expectGuessRegistrarSuccess(
|
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
AUTHORIZED_ADMIN,
|
new AuthenticatedRegistrarAccessor(AUTHORIZED_ADMIN, ADMIN_CLIENT_ID);
|
||||||
DEFAULT_CLIENT_ID,
|
|
||||||
"Associating user {user} with found registrar {clientId}.");
|
assertThat(registrarAccessor.guessClientId()).isEqualTo(DEFAULT_CLIENT_ID);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** If an admin doesn't have access to a registrar, we should guess the ADMIN_CLIENT_ID. */
|
/** If an admin doesn't have access to a registrar, we should guess the ADMIN_CLIENT_ID. */
|
||||||
@Test
|
@Test
|
||||||
public void testGuessClientIdForUser_noAccess_isAdmin() {
|
public void testGuessClientIdForUser_noAccess_isAdmin() {
|
||||||
expectGuessRegistrarSuccess(
|
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
UNAUTHORIZED_ADMIN,
|
new AuthenticatedRegistrarAccessor(UNAUTHORIZED_ADMIN, ADMIN_CLIENT_ID);
|
||||||
ADMIN_CLIENT_ID,
|
|
||||||
"User {user} is an admin with no associated registrar."
|
assertThat(registrarAccessor.guessClientId()).isEqualTo(ADMIN_CLIENT_ID);
|
||||||
+ " Automatically associating the user with configured client Id {clientId}.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* If an admin is not associated with a registrar and there is no configured adminClientId, we
|
* If an admin is not associated with a registrar and there is no configured adminClientId, but
|
||||||
* can't guess the clientId.
|
* since it's an admin - we have read-only access to everything - return one of the existing
|
||||||
|
* registrars.
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGuessClientIdForUser_noAccess_isAdmin_adminClientIdEmpty() {
|
public void testGuessClientIdForUser_noAccess_isAdmin_adminClientIdEmpty() {
|
||||||
sessionUtils.registryAdminClientId = "";
|
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
expectGuessRegistrarFailure(
|
new AuthenticatedRegistrarAccessor(UNAUTHORIZED_ADMIN, "");
|
||||||
UNAUTHORIZED_ADMIN, "User {user} isn't associated with any registrar");
|
|
||||||
assertAboutLogs()
|
assertThat(registrarAccessor.guessClientId()).isAnyOf(ADMIN_CLIENT_ID, DEFAULT_CLIENT_ID);
|
||||||
.that(testLogHandler)
|
|
||||||
.hasLogAtLevelWithMessage(
|
|
||||||
Level.INFO,
|
|
||||||
formatMessage(
|
|
||||||
"Cannot associate admin user {user} with configured client Id."
|
|
||||||
+ " ClientId is null or empty.",
|
|
||||||
UNAUTHORIZED_ADMIN,
|
|
||||||
null));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -283,24 +334,18 @@ public class SessionUtilsTest {
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testGuessClientIdForUser_noAccess_isAdmin_adminClientIdInvalid() {
|
public void testGuessClientIdForUser_noAccess_isAdmin_adminClientIdInvalid() {
|
||||||
sessionUtils.registryAdminClientId = "NonexistentRegistrar";
|
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
expectGuessRegistrarSuccess(
|
new AuthenticatedRegistrarAccessor(UNAUTHORIZED_ADMIN, "NonexistentRegistrar");
|
||||||
UNAUTHORIZED_ADMIN,
|
|
||||||
"NonexistentRegistrar",
|
|
||||||
"User {user} is an admin with no associated registrar."
|
|
||||||
+ " Automatically associating the user with configured client Id {clientId}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void expectGuessRegistrarSuccess(AuthResult authResult, String clientId, String message) {
|
assertThat(registrarAccessor.guessClientId()).isEqualTo("NonexistentRegistrar");
|
||||||
assertThat(sessionUtils.guessClientIdForUser(authResult)).isEqualTo(clientId);
|
|
||||||
assertAboutLogs()
|
|
||||||
.that(testLogHandler)
|
|
||||||
.hasLogAtLevelWithMessage(Level.INFO, formatMessage(message, authResult, clientId));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private void expectGuessRegistrarFailure(AuthResult authResult, String message) {
|
private void expectGuessRegistrarFailure(AuthResult authResult, String message) {
|
||||||
|
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
|
new AuthenticatedRegistrarAccessor(authResult, ADMIN_CLIENT_ID);
|
||||||
|
|
||||||
ForbiddenException exception =
|
ForbiddenException exception =
|
||||||
assertThrows(ForbiddenException.class, () -> sessionUtils.guessClientIdForUser(authResult));
|
assertThrows(ForbiddenException.class, () -> registrarAccessor.guessClientId());
|
||||||
assertThat(exception)
|
assertThat(exception)
|
||||||
.hasMessageThat()
|
.hasMessageThat()
|
||||||
.contains(formatMessage(message, authResult, null));
|
.contains(formatMessage(message, authResult, null));
|
||||||
|
@ -311,6 +356,6 @@ public class SessionUtilsTest {
|
||||||
new NullPointerTester()
|
new NullPointerTester()
|
||||||
.setDefault(HttpServletRequest.class, req)
|
.setDefault(HttpServletRequest.class, req)
|
||||||
.setDefault(HttpServletResponse.class, rsp)
|
.setDefault(HttpServletResponse.class, rsp)
|
||||||
.testAllPublicStaticMethods(SessionUtils.class);
|
.testAllPublicStaticMethods(AuthenticatedRegistrarAccessor.class);
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -17,14 +17,15 @@ package google.registry.ui.server.registrar;
|
||||||
import static com.google.common.net.HttpHeaders.LOCATION;
|
import static com.google.common.net.HttpHeaders.LOCATION;
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static google.registry.testing.DatastoreHelper.loadRegistrar;
|
import static google.registry.testing.DatastoreHelper.loadRegistrar;
|
||||||
import static google.registry.ui.server.registrar.SessionUtils.AccessType.READ_ONLY;
|
import static google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor.AccessType.READ;
|
||||||
|
import static google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor.AccessType.UPDATE;
|
||||||
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
|
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
|
||||||
import static org.mockito.Matchers.any;
|
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.google.appengine.api.users.User;
|
import com.google.appengine.api.users.User;
|
||||||
import com.google.appengine.api.users.UserServiceFactory;
|
import com.google.appengine.api.users.UserServiceFactory;
|
||||||
|
import com.google.common.collect.ImmutableSetMultimap;
|
||||||
import com.google.common.net.MediaType;
|
import com.google.common.net.MediaType;
|
||||||
import google.registry.request.HttpException.ForbiddenException;
|
import google.registry.request.HttpException.ForbiddenException;
|
||||||
import google.registry.request.auth.AuthLevel;
|
import google.registry.request.auth.AuthLevel;
|
||||||
|
@ -53,7 +54,8 @@ public class ConsoleUiActionTest {
|
||||||
.withUserService(UserInfo.create("marla.singer@example.com", "12345"))
|
.withUserService(UserInfo.create("marla.singer@example.com", "12345"))
|
||||||
.build();
|
.build();
|
||||||
|
|
||||||
private final SessionUtils sessionUtils = mock(SessionUtils.class);
|
private final AuthenticatedRegistrarAccessor registrarAccessor =
|
||||||
|
mock(AuthenticatedRegistrarAccessor.class);
|
||||||
private final HttpServletRequest request = mock(HttpServletRequest.class);
|
private final HttpServletRequest request = mock(HttpServletRequest.class);
|
||||||
private final FakeResponse response = new FakeResponse();
|
private final FakeResponse response = new FakeResponse();
|
||||||
private final ConsoleUiAction action = new ConsoleUiAction();
|
private final ConsoleUiAction action = new ConsoleUiAction();
|
||||||
|
@ -71,15 +73,25 @@ public class ConsoleUiActionTest {
|
||||||
action.technicalDocsUrl = "http://example.com/technical-docs";
|
action.technicalDocsUrl = "http://example.com/technical-docs";
|
||||||
action.req = request;
|
action.req = request;
|
||||||
action.response = response;
|
action.response = response;
|
||||||
action.sessionUtils = sessionUtils;
|
action.registrarAccessor = registrarAccessor;
|
||||||
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.paramClientId = Optional.empty();
|
action.paramClientId = Optional.empty();
|
||||||
AuthResult authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
|
AuthResult authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
|
||||||
action.authResult = authResult;
|
action.authResult = authResult;
|
||||||
when(sessionUtils.guessClientIdForUser(authResult)).thenReturn("TheRegistrar");
|
when(registrarAccessor.getRegistrar("TheRegistrar", READ))
|
||||||
when(sessionUtils.getRegistrarForUser("TheRegistrar", READ_ONLY, authResult))
|
|
||||||
.thenReturn(loadRegistrar("TheRegistrar"));
|
.thenReturn(loadRegistrar("TheRegistrar"));
|
||||||
|
when(registrarAccessor.getAllClientIdWithAccess())
|
||||||
|
.thenReturn(
|
||||||
|
ImmutableSetMultimap.of(
|
||||||
|
UPDATE, "TheRegistrar",
|
||||||
|
READ, "TheRegistrar",
|
||||||
|
UPDATE, "ReadWriteRegistrar",
|
||||||
|
READ, "ReadWriteRegistrar",
|
||||||
|
READ, "ReadOnlyRegistrar"));
|
||||||
|
when(registrarAccessor.guessClientId()).thenCallRealMethod();
|
||||||
|
// Used for error message in guessClientId
|
||||||
|
registrarAccessor.authResult = authResult;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
|
@ -116,8 +128,7 @@ public class ConsoleUiActionTest {
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testUserDoesntHaveAccessToAnyRegistrar_showsWhoAreYouPage() {
|
public void testUserDoesntHaveAccessToAnyRegistrar_showsWhoAreYouPage() {
|
||||||
when(sessionUtils.guessClientIdForUser(any(AuthResult.class)))
|
when(registrarAccessor.getAllClientIdWithAccess()).thenReturn(ImmutableSetMultimap.of());
|
||||||
.thenThrow(new ForbiddenException("forbidden"));
|
|
||||||
action.run();
|
action.run();
|
||||||
assertThat(response.getPayload()).contains("<h1>You need permission</h1>");
|
assertThat(response.getPayload()).contains("<h1>You need permission</h1>");
|
||||||
assertThat(response.getPayload()).contains("not associated with Nomulus.");
|
assertThat(response.getPayload()).contains("not associated with Nomulus.");
|
||||||
|
@ -144,7 +155,7 @@ public class ConsoleUiActionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testSettingClientId_notAllowed_showsNeedPermissionPage() {
|
public void testSettingClientId_notAllowed_showsNeedPermissionPage() {
|
||||||
action.paramClientId = Optional.of("OtherClientId");
|
action.paramClientId = Optional.of("OtherClientId");
|
||||||
when(sessionUtils.getRegistrarForUser("OtherClientId", READ_ONLY, action.authResult))
|
when(registrarAccessor.getRegistrar("OtherClientId", READ))
|
||||||
.thenThrow(new ForbiddenException("forbidden"));
|
.thenThrow(new ForbiddenException("forbidden"));
|
||||||
action.run();
|
action.run();
|
||||||
assertThat(response.getPayload()).contains("<h1>You need permission</h1>");
|
assertThat(response.getPayload()).contains("<h1>You need permission</h1>");
|
||||||
|
@ -154,10 +165,18 @@ public class ConsoleUiActionTest {
|
||||||
@Test
|
@Test
|
||||||
public void testSettingClientId_allowed_showsRegistrarConsole() {
|
public void testSettingClientId_allowed_showsRegistrarConsole() {
|
||||||
action.paramClientId = Optional.of("OtherClientId");
|
action.paramClientId = Optional.of("OtherClientId");
|
||||||
when(sessionUtils.getRegistrarForUser("OtherClientId", READ_ONLY, action.authResult))
|
when(registrarAccessor.getRegistrar("OtherClientId", READ))
|
||||||
.thenReturn(loadRegistrar("TheRegistrar"));
|
.thenReturn(loadRegistrar("TheRegistrar"));
|
||||||
action.run();
|
action.run();
|
||||||
assertThat(response.getPayload()).contains("Registrar Console");
|
assertThat(response.getPayload()).contains("Registrar Console");
|
||||||
assertThat(response.getPayload()).contains("reg-content-and-footer");
|
assertThat(response.getPayload()).contains("reg-content-and-footer");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testUserHasAccessAsTheRegistrar_showsClientIdChooser() {
|
||||||
|
action.run();
|
||||||
|
assertThat(response.getPayload()).contains("<option value=\"TheRegistrar\" selected>");
|
||||||
|
assertThat(response.getPayload()).contains("<option value=\"ReadWriteRegistrar\">");
|
||||||
|
assertThat(response.getPayload()).contains("<option value=\"ReadOnlyRegistrar\">");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -81,7 +81,7 @@ public class RegistrarSettingsActionTest extends RegistrarSettingsActionTestCase
|
||||||
*/
|
*/
|
||||||
@Test
|
@Test
|
||||||
public void testFailure_readRegistrarInfo_notAuthorized() {
|
public void testFailure_readRegistrarInfo_notAuthorized() {
|
||||||
action.authResult = USER_UNAUTHORIZED;
|
setUserWithoutAccess();
|
||||||
Map<String, Object> response = action.handleJsonRequest(ImmutableMap.of("id", CLIENT_ID));
|
Map<String, Object> response = action.handleJsonRequest(ImmutableMap.of("id", CLIENT_ID));
|
||||||
assertThat(response).containsExactly(
|
assertThat(response).containsExactly(
|
||||||
"status", "ERROR",
|
"status", "ERROR",
|
||||||
|
@ -104,7 +104,7 @@ public class RegistrarSettingsActionTest extends RegistrarSettingsActionTestCase
|
||||||
/** This is the default read test for the registrar settings actions. */
|
/** This is the default read test for the registrar settings actions. */
|
||||||
@Test
|
@Test
|
||||||
public void testSuccess_readRegistrarInfo_authorizedReadOnly() {
|
public void testSuccess_readRegistrarInfo_authorizedReadOnly() {
|
||||||
action.authResult = USER_READ_ONLY;
|
setUserReadOnlyAccess();
|
||||||
Map<String, Object> response = action.handleJsonRequest(ImmutableMap.of("id", CLIENT_ID));
|
Map<String, Object> response = action.handleJsonRequest(ImmutableMap.of("id", CLIENT_ID));
|
||||||
assertThat(response)
|
assertThat(response)
|
||||||
.containsExactly(
|
.containsExactly(
|
||||||
|
@ -157,7 +157,7 @@ public class RegistrarSettingsActionTest extends RegistrarSettingsActionTestCase
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFailure_updateRegistrarInfo_notAuthorized() {
|
public void testFailure_updateRegistrarInfo_notAuthorized() {
|
||||||
action.authResult = USER_UNAUTHORIZED;
|
setUserWithoutAccess();
|
||||||
Map<String, Object> response = action.handleJsonRequest(ImmutableMap.of(
|
Map<String, Object> response = action.handleJsonRequest(ImmutableMap.of(
|
||||||
"op", "update",
|
"op", "update",
|
||||||
"id", CLIENT_ID,
|
"id", CLIENT_ID,
|
||||||
|
@ -171,7 +171,7 @@ public class RegistrarSettingsActionTest extends RegistrarSettingsActionTestCase
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testFailure_updateRegistrarInfo_readOnlyAccess() {
|
public void testFailure_updateRegistrarInfo_readOnlyAccess() {
|
||||||
action.authResult = USER_READ_ONLY;
|
setUserReadOnlyAccess();
|
||||||
Map<String, Object> response = action.handleJsonRequest(ImmutableMap.of(
|
Map<String, Object> response = action.handleJsonRequest(ImmutableMap.of(
|
||||||
"op", "update",
|
"op", "update",
|
||||||
"id", CLIENT_ID,
|
"id", CLIENT_ID,
|
||||||
|
|
|
@ -18,8 +18,9 @@ import static google.registry.config.RegistryConfig.getGSuiteOutgoingEmailAddres
|
||||||
import static google.registry.config.RegistryConfig.getGSuiteOutgoingEmailDisplayName;
|
import static google.registry.config.RegistryConfig.getGSuiteOutgoingEmailDisplayName;
|
||||||
import static google.registry.security.JsonHttpTestUtils.createJsonPayload;
|
import static google.registry.security.JsonHttpTestUtils.createJsonPayload;
|
||||||
import static google.registry.testing.DatastoreHelper.loadRegistrar;
|
import static google.registry.testing.DatastoreHelper.loadRegistrar;
|
||||||
import static google.registry.ui.server.registrar.SessionUtils.AccessType.READ_ONLY;
|
import static google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor.AccessType.READ;
|
||||||
import static google.registry.ui.server.registrar.SessionUtils.AccessType.READ_WRITE;
|
import static google.registry.ui.server.registrar.AuthenticatedRegistrarAccessor.AccessType.UPDATE;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.google.appengine.api.users.User;
|
import com.google.appengine.api.users.User;
|
||||||
|
@ -30,9 +31,6 @@ import google.registry.request.HttpException.ForbiddenException;
|
||||||
import google.registry.request.JsonActionRunner;
|
import google.registry.request.JsonActionRunner;
|
||||||
import google.registry.request.JsonResponse;
|
import google.registry.request.JsonResponse;
|
||||||
import google.registry.request.ResponseImpl;
|
import google.registry.request.ResponseImpl;
|
||||||
import google.registry.request.auth.AuthLevel;
|
|
||||||
import google.registry.request.auth.AuthResult;
|
|
||||||
import google.registry.request.auth.UserAuthInfo;
|
|
||||||
import google.registry.testing.AppEngineRule;
|
import google.registry.testing.AppEngineRule;
|
||||||
import google.registry.testing.FakeClock;
|
import google.registry.testing.FakeClock;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
|
@ -60,15 +58,6 @@ public class RegistrarSettingsActionTestCase {
|
||||||
|
|
||||||
static final String CLIENT_ID = "TheRegistrar";
|
static final String CLIENT_ID = "TheRegistrar";
|
||||||
|
|
||||||
static final AuthResult USER_READ_WRITE =
|
|
||||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(new User("rw", "gmail.com"), false));
|
|
||||||
|
|
||||||
static final AuthResult USER_READ_ONLY =
|
|
||||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(new User("ro", "gmail.com"), false));
|
|
||||||
|
|
||||||
static final AuthResult USER_UNAUTHORIZED =
|
|
||||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(new User("evil", "gmail.com"), false));
|
|
||||||
|
|
||||||
@Rule
|
@Rule
|
||||||
public final AppEngineRule appEngine =
|
public final AppEngineRule appEngine =
|
||||||
AppEngineRule.builder().withDatastore().withTaskQueue().build();
|
AppEngineRule.builder().withDatastore().withTaskQueue().build();
|
||||||
|
@ -80,7 +69,6 @@ public class RegistrarSettingsActionTestCase {
|
||||||
@Mock HttpServletRequest req;
|
@Mock HttpServletRequest req;
|
||||||
@Mock HttpServletResponse rsp;
|
@Mock HttpServletResponse rsp;
|
||||||
@Mock SendEmailService emailService;
|
@Mock SendEmailService emailService;
|
||||||
@Mock SessionUtils sessionUtils;
|
|
||||||
final User user = new User("user", "gmail.com");
|
final User user = new User("user", "gmail.com");
|
||||||
|
|
||||||
Message message;
|
Message message;
|
||||||
|
@ -91,12 +79,9 @@ public class RegistrarSettingsActionTestCase {
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
action.sessionUtils = sessionUtils;
|
action.registrarAccessor = null;
|
||||||
action.appEngineServiceUtils = appEngineServiceUtils;
|
action.appEngineServiceUtils = appEngineServiceUtils;
|
||||||
when(appEngineServiceUtils.getCurrentVersionHostname("backend")).thenReturn("backend.hostname");
|
when(appEngineServiceUtils.getCurrentVersionHostname("backend")).thenReturn("backend.hostname");
|
||||||
// We set the default user to one with read-write access, as that's the most common test case.
|
|
||||||
// When we want to specifically check read-only or unauthorized, we can switch the user here.
|
|
||||||
action.authResult = USER_READ_WRITE;
|
|
||||||
action.jsonActionRunner = new JsonActionRunner(
|
action.jsonActionRunner = new JsonActionRunner(
|
||||||
ImmutableMap.of(), new JsonResponse(new ResponseImpl(rsp)));
|
ImmutableMap.of(), new JsonResponse(new ResponseImpl(rsp)));
|
||||||
action.registrarChangesNotificationEmailAddresses = ImmutableList.of(
|
action.registrarChangesNotificationEmailAddresses = ImmutableList.of(
|
||||||
|
@ -111,23 +96,41 @@ public class RegistrarSettingsActionTestCase {
|
||||||
when(rsp.getWriter()).thenReturn(new PrintWriter(writer));
|
when(rsp.getWriter()).thenReturn(new PrintWriter(writer));
|
||||||
when(req.getContentType()).thenReturn("application/json");
|
when(req.getContentType()).thenReturn("application/json");
|
||||||
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of("op", "read")));
|
when(req.getReader()).thenReturn(createJsonPayload(ImmutableMap.of("op", "read")));
|
||||||
// We mock getRegistrarForAuthResult to reload the registrar each time it's called. Otherwise -
|
// We set the default user to one with read-write access, as that's the most common test case.
|
||||||
// the result is out of date after mutations.
|
// When we want to specifically check read-only or unauthorized, we can switch the user here.
|
||||||
// (for example, if someone wants to change the registrar to prepare for a test, the function
|
setUserReadWriteAccess();
|
||||||
// would still return the old value)
|
}
|
||||||
when(sessionUtils.getRegistrarForUser(CLIENT_ID, READ_ONLY, USER_READ_WRITE))
|
|
||||||
.thenAnswer(x -> loadRegistrar(CLIENT_ID));
|
/** Sets registrarAccessor.getRegistrar to succeed for all AccessTypes. */
|
||||||
when(sessionUtils.getRegistrarForUser(CLIENT_ID, READ_WRITE, USER_READ_WRITE))
|
protected void setUserReadWriteAccess() {
|
||||||
|
action.registrarAccessor = mock(AuthenticatedRegistrarAccessor.class);
|
||||||
|
|
||||||
|
when(action.registrarAccessor.getRegistrar(CLIENT_ID, READ))
|
||||||
.thenAnswer(x -> loadRegistrar(CLIENT_ID));
|
.thenAnswer(x -> loadRegistrar(CLIENT_ID));
|
||||||
|
|
||||||
when(sessionUtils.getRegistrarForUser(CLIENT_ID, READ_ONLY, USER_READ_ONLY))
|
when(action.registrarAccessor.getRegistrar(CLIENT_ID, UPDATE))
|
||||||
.thenAnswer(x -> loadRegistrar(CLIENT_ID));
|
.thenAnswer(x -> loadRegistrar(CLIENT_ID));
|
||||||
when(sessionUtils.getRegistrarForUser(CLIENT_ID, READ_WRITE, USER_READ_ONLY))
|
}
|
||||||
|
|
||||||
|
/** Sets registrarAccessor.getRegistrar to only succeed for READ. */
|
||||||
|
protected void setUserReadOnlyAccess() {
|
||||||
|
action.registrarAccessor = mock(AuthenticatedRegistrarAccessor.class);
|
||||||
|
|
||||||
|
when(action.registrarAccessor.getRegistrar(CLIENT_ID, READ))
|
||||||
|
.thenAnswer(x -> loadRegistrar(CLIENT_ID));
|
||||||
|
|
||||||
|
when(action.registrarAccessor.getRegistrar(CLIENT_ID, UPDATE))
|
||||||
|
.thenThrow(new ForbiddenException("forbidden test error"));
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Sets registrarAccessor.getRegistrar to always fail. */
|
||||||
|
protected void setUserWithoutAccess() {
|
||||||
|
action.registrarAccessor = mock(AuthenticatedRegistrarAccessor.class);
|
||||||
|
|
||||||
|
when(action.registrarAccessor.getRegistrar(CLIENT_ID, READ))
|
||||||
.thenThrow(new ForbiddenException("forbidden test error"));
|
.thenThrow(new ForbiddenException("forbidden test error"));
|
||||||
|
|
||||||
when(sessionUtils.getRegistrarForUser(CLIENT_ID, READ_ONLY, USER_UNAUTHORIZED))
|
when(action.registrarAccessor.getRegistrar(CLIENT_ID, UPDATE))
|
||||||
.thenThrow(new ForbiddenException("forbidden test error"));
|
|
||||||
when(sessionUtils.getRegistrarForUser(CLIENT_ID, READ_WRITE, USER_UNAUTHORIZED))
|
|
||||||
.thenThrow(new ForbiddenException("forbidden test error"));
|
.thenThrow(new ForbiddenException("forbidden test error"));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue