mirror of
https://github.com/google/nomulus.git
synced 2025-05-14 08:27:14 +02:00
Allow admins to access registrar console without a RegistrarContact
This allows admins to access the registrar console without needing to be added as a registrar contact. If they are a registrar contact, then that registrar takes precedence. Tested=In Alpha ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=164182623
This commit is contained in:
parent
151ae2558f
commit
f3919e056d
9 changed files with 308 additions and 69 deletions
|
@ -931,6 +931,16 @@ public final class RegistryConfig {
|
|||
return config.registryPolicy.checkApiServletClientId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the clientId of the registrar that admins are automatically logged in as if they
|
||||
* aren't otherwise associated with one.
|
||||
*/
|
||||
@Provides
|
||||
@Config("registryAdminClientId")
|
||||
public static String provideRegistryAdminClientId(RegistryConfigSettings config) {
|
||||
return config.registryPolicy.registryAdminClientId;
|
||||
}
|
||||
|
||||
@Singleton
|
||||
@Provides
|
||||
static RegistryConfigSettings provideRegistryConfigSettings() {
|
||||
|
|
|
@ -78,6 +78,7 @@ public class RegistryConfigSettings {
|
|||
public String tmchCrlUrl;
|
||||
public String tmchMarksDbUrl;
|
||||
public String checkApiServletClientId;
|
||||
public String registryAdminClientId;
|
||||
public String reservedTermsExportDisclaimer;
|
||||
public String whoisDisclaimer;
|
||||
}
|
||||
|
|
|
@ -71,6 +71,11 @@ registryPolicy:
|
|||
# domain checks.
|
||||
checkApiServletClientId: TheRegistrar
|
||||
|
||||
# The registry admin's registrar. Admins are granted permission to log in
|
||||
# using this registrar automatically if they are not associated with any
|
||||
# registrar
|
||||
registryAdminClientId: TheRegistrar
|
||||
|
||||
# Disclaimer at the top of the exported reserved terms list.
|
||||
reservedTermsExportDisclaimer: |
|
||||
This list contains reserved terms for the TLD. Other terms may be reserved
|
||||
|
|
|
@ -29,6 +29,7 @@ registryPolicy:
|
|||
tmchCrlUrl: http://crl.icann.org/tmch.crl
|
||||
tmchMarksDbUrl: https://ry.marksdb.org
|
||||
checkApiServletClientId: placeholder
|
||||
registryAdminClientId: placeholder
|
||||
whoisDisclaimer: |
|
||||
multi-line
|
||||
placeholder
|
||||
|
|
|
@ -21,7 +21,6 @@ import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;
|
|||
import static javax.servlet.http.HttpServletResponse.SC_MOVED_TEMPORARILY;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_SERVICE_UNAVAILABLE;
|
||||
|
||||
import com.google.appengine.api.users.User;
|
||||
import com.google.appengine.api.users.UserService;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Supplier;
|
||||
|
@ -36,6 +35,7 @@ import google.registry.request.Action;
|
|||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.UserAuthInfo;
|
||||
import google.registry.security.XsrfTokenManager;
|
||||
import google.registry.ui.server.SoyTemplateUtils;
|
||||
import google.registry.ui.soy.registrar.ConsoleSoyInfo;
|
||||
|
@ -97,7 +97,7 @@ public final class ConsoleUiAction implements Runnable {
|
|||
response.setHeader(LOCATION, location);
|
||||
return;
|
||||
}
|
||||
User user = authResult.userAuthInfo().get().user();
|
||||
UserAuthInfo userAuthInfo = authResult.userAuthInfo().get();
|
||||
response.setContentType(MediaType.HTML_UTF_8);
|
||||
response.setHeader(X_FRAME_OPTIONS, "SAMEORIGIN"); // Disallow iframing.
|
||||
response.setHeader("X-Ui-Compatible", "IE=edge"); // Ask IE not to be silly.
|
||||
|
@ -119,9 +119,9 @@ public final class ConsoleUiAction implements Runnable {
|
|||
.render());
|
||||
return;
|
||||
}
|
||||
data.put("username", user.getNickname());
|
||||
data.put("username", userAuthInfo.user().getNickname());
|
||||
data.put("logoutUrl", userService.createLogoutURL(PATH));
|
||||
if (!sessionUtils.checkRegistrarConsoleLogin(req, user)) {
|
||||
if (!sessionUtils.checkRegistrarConsoleLogin(req, userAuthInfo)) {
|
||||
response.setStatus(SC_FORBIDDEN);
|
||||
response.setPayload(
|
||||
TOFU_SUPPLIER.get()
|
||||
|
@ -135,7 +135,7 @@ public final class ConsoleUiAction implements Runnable {
|
|||
Registrar registrar =
|
||||
checkArgumentPresent(
|
||||
Registrar.loadByClientIdCached(clientId), "Registrar %s does not exist", clientId);
|
||||
data.put("xsrfToken", xsrfTokenManager.generateToken(user.getEmail()));
|
||||
data.put("xsrfToken", xsrfTokenManager.generateToken(userAuthInfo.user().getEmail()));
|
||||
data.put("clientId", clientId);
|
||||
data.put("showPaymentLink", registrar.getBillingMethod() == Registrar.BillingMethod.BRAINTREE);
|
||||
|
||||
|
|
|
@ -22,12 +22,15 @@ import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
|
|||
import com.google.appengine.api.users.User;
|
||||
import com.google.common.base.Optional;
|
||||
import com.google.common.base.Predicate;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.collect.FluentIterable;
|
||||
import com.googlecode.objectify.Key;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.model.registrar.Registrar;
|
||||
import google.registry.model.registrar.RegistrarContact;
|
||||
import google.registry.request.HttpException.ForbiddenException;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
import google.registry.request.auth.UserAuthInfo;
|
||||
import google.registry.util.FormattingLogger;
|
||||
import javax.annotation.CheckReturnValue;
|
||||
import javax.annotation.Nonnull;
|
||||
|
@ -40,10 +43,14 @@ import javax.servlet.http.HttpSession;
|
|||
@Immutable
|
||||
public class SessionUtils {
|
||||
|
||||
private static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
|
||||
static final FormattingLogger logger = FormattingLogger.getLoggerForCallerClass();
|
||||
|
||||
public static final String CLIENT_ID_ATTRIBUTE = "clientId";
|
||||
|
||||
@Inject
|
||||
@Config("registryAdminClientId")
|
||||
String registryAdminClientId;
|
||||
|
||||
@Inject public SessionUtils() {}
|
||||
|
||||
/**
|
||||
|
@ -58,7 +65,7 @@ public class SessionUtils {
|
|||
if (!authResult.userAuthInfo().isPresent()) {
|
||||
throw new ForbiddenException("Not logged in");
|
||||
}
|
||||
if (!checkRegistrarConsoleLogin(request, authResult.userAuthInfo().get().user())) {
|
||||
if (!checkRegistrarConsoleLogin(request, authResult.userAuthInfo().get())) {
|
||||
throw new ForbiddenException("Not authorized to access Registrar Console");
|
||||
}
|
||||
String clientId = getRegistrarClientId(request);
|
||||
|
@ -86,28 +93,62 @@ public class SessionUtils {
|
|||
* error response and abort the request.
|
||||
*/
|
||||
@CheckReturnValue
|
||||
public boolean checkRegistrarConsoleLogin(HttpServletRequest req, User user) {
|
||||
checkState(user != null, "No logged in user found");
|
||||
public boolean checkRegistrarConsoleLogin(HttpServletRequest req, UserAuthInfo userAuthInfo) {
|
||||
checkState(userAuthInfo != null, "No logged in user found");
|
||||
User user = userAuthInfo.user();
|
||||
HttpSession session = req.getSession();
|
||||
String clientId = (String) session.getAttribute(CLIENT_ID_ATTRIBUTE);
|
||||
if (clientId == null) {
|
||||
Optional<Registrar> registrar = guessRegistrar(user.getUserId());
|
||||
if (!registrar.isPresent()) {
|
||||
logger.infofmt("User not associated with any Registrar: %s (%s)",
|
||||
user.getUserId(), user.getEmail());
|
||||
return false;
|
||||
}
|
||||
verify(hasAccessToRegistrar(registrar.get(), user.getUserId()));
|
||||
session.setAttribute(CLIENT_ID_ATTRIBUTE, registrar.get().getClientId());
|
||||
} else {
|
||||
|
||||
// Use the clientId if it exists
|
||||
if (clientId != null) {
|
||||
if (!hasAccessToRegistrar(clientId, user.getUserId())) {
|
||||
logger.infofmt("Registrar Console access revoked: %s for %s (%s)",
|
||||
clientId, user.getEmail(), user.getUserId());
|
||||
logger.infofmt("Registrar Console access revoked: %s", clientId);
|
||||
session.invalidate();
|
||||
return false;
|
||||
}
|
||||
logger.infofmt("Associating user %s with given registrar %s.", user.getUserId(), clientId);
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
|
||||
// The clientId was null, so let's try and find a registrar this user is associated with
|
||||
Optional<Registrar> registrar = findRegistrarForUser(user.getUserId());
|
||||
if (registrar.isPresent()) {
|
||||
verify(hasAccessToRegistrar(registrar.get(), user.getUserId()));
|
||||
logger.infofmt(
|
||||
"Associating user %s with found registrar %s.",
|
||||
user.getUserId(), registrar.get().getClientId());
|
||||
session.setAttribute(CLIENT_ID_ATTRIBUTE, registrar.get().getClientId());
|
||||
return true;
|
||||
}
|
||||
|
||||
// We couldn't guess the registrar, but maybe the user is an admin and we can use the
|
||||
// registryAdminClientId
|
||||
if (userAuthInfo.isUserAdmin()) {
|
||||
if (Strings.isNullOrEmpty(registryAdminClientId)) {
|
||||
logger.infofmt(
|
||||
"Cannot associate admin user %s with configured client Id."
|
||||
+ " ClientId is null or empty.",
|
||||
user.getUserId());
|
||||
return false;
|
||||
}
|
||||
if (!Registrar.loadByClientIdCached(registryAdminClientId).isPresent()) {
|
||||
logger.infofmt(
|
||||
"Cannot associate admin user %s with configured client Id %s."
|
||||
+ " Registrar does not exist.",
|
||||
user.getUserId(), registryAdminClientId);
|
||||
return false;
|
||||
}
|
||||
logger.infofmt(
|
||||
"User %s is an admin with no associated registrar."
|
||||
+ " Automatically associating the user with configured client Id %s.",
|
||||
user.getUserId(), registryAdminClientId);
|
||||
session.setAttribute(CLIENT_ID_ATTRIBUTE, registryAdminClientId);
|
||||
return true;
|
||||
}
|
||||
|
||||
// We couldn't find any relevant clientId
|
||||
logger.infofmt("User not associated with any Registrar: %s", user.getUserId());
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -123,7 +164,7 @@ public class SessionUtils {
|
|||
}
|
||||
|
||||
/** Returns first {@link Registrar} that {@code gaeUserId} is authorized to administer. */
|
||||
private static Optional<Registrar> guessRegistrar(String gaeUserId) {
|
||||
private static Optional<Registrar> findRegistrarForUser(String gaeUserId) {
|
||||
RegistrarContact contact = ofy().load()
|
||||
.type(RegistrarContact.class)
|
||||
.filter("gaeUserId", gaeUserId)
|
||||
|
@ -141,7 +182,7 @@ public class SessionUtils {
|
|||
}
|
||||
|
||||
/** @see #hasAccessToRegistrar(Registrar, String) */
|
||||
private static boolean hasAccessToRegistrar(String clientId, final String gaeUserId) {
|
||||
protected static boolean hasAccessToRegistrar(String clientId, final String gaeUserId) {
|
||||
Optional<Registrar> registrar = Registrar.loadByClientIdCached(clientId);
|
||||
if (!registrar.isPresent()) {
|
||||
logger.warningfmt("Registrar '%s' disappeared from Datastore!", clientId);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue