mirror of
https://github.com/google/nomulus.git
synced 2025-05-13 16:07:15 +02:00
Add RDAP support for deleted nameservers and filtering by registrar
This CL adds the functionality for nameserver searches. Future CLs will handle domains and entities. Deleted items can only be seen by admins, and by registrars viewing their own deleted items. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=170106014
This commit is contained in:
parent
0c8b5bc8bf
commit
c13c2f403a
11 changed files with 870 additions and 153 deletions
|
@ -15,6 +15,7 @@
|
||||||
package google.registry.rdap;
|
package google.registry.rdap;
|
||||||
|
|
||||||
import static com.google.common.base.Preconditions.checkArgument;
|
import static com.google.common.base.Preconditions.checkArgument;
|
||||||
|
import static com.google.common.base.Preconditions.checkState;
|
||||||
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.model.registry.Registries.findTldForName;
|
import static google.registry.model.registry.Registries.findTldForName;
|
||||||
|
@ -30,15 +31,18 @@ import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.net.InternetDomainName;
|
import com.google.common.net.InternetDomainName;
|
||||||
import com.google.common.net.MediaType;
|
import com.google.common.net.MediaType;
|
||||||
import com.google.re2j.Pattern;
|
import com.google.re2j.Pattern;
|
||||||
|
import com.googlecode.objectify.Key;
|
||||||
import com.googlecode.objectify.cmd.Query;
|
import com.googlecode.objectify.cmd.Query;
|
||||||
import google.registry.config.RegistryConfig.Config;
|
import google.registry.config.RegistryConfig.Config;
|
||||||
import google.registry.model.EppResource;
|
import google.registry.model.EppResource;
|
||||||
import google.registry.model.registrar.Registrar;
|
import google.registry.model.registrar.Registrar;
|
||||||
|
import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
|
||||||
import google.registry.request.Action;
|
import google.registry.request.Action;
|
||||||
import google.registry.request.HttpException;
|
import google.registry.request.HttpException;
|
||||||
import google.registry.request.HttpException.BadRequestException;
|
import google.registry.request.HttpException.BadRequestException;
|
||||||
import google.registry.request.HttpException.NotFoundException;
|
import google.registry.request.HttpException.NotFoundException;
|
||||||
import google.registry.request.HttpException.UnprocessableEntityException;
|
import google.registry.request.HttpException.UnprocessableEntityException;
|
||||||
|
import google.registry.request.Parameter;
|
||||||
import google.registry.request.RequestMethod;
|
import google.registry.request.RequestMethod;
|
||||||
import google.registry.request.RequestPath;
|
import google.registry.request.RequestPath;
|
||||||
import google.registry.request.Response;
|
import google.registry.request.Response;
|
||||||
|
@ -48,9 +52,12 @@ import google.registry.ui.server.registrar.SessionUtils;
|
||||||
import google.registry.util.FormattingLogger;
|
import google.registry.util.FormattingLogger;
|
||||||
import java.net.URI;
|
import java.net.URI;
|
||||||
import java.net.URISyntaxException;
|
import java.net.URISyntaxException;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.inject.Inject;
|
import javax.inject.Inject;
|
||||||
import javax.servlet.http.HttpServletRequest;
|
import javax.servlet.http.HttpServletRequest;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
import org.json.simple.JSONValue;
|
import org.json.simple.JSONValue;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -78,8 +85,11 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
@Inject AuthResult authResult;
|
@Inject AuthResult authResult;
|
||||||
@Inject SessionUtils sessionUtils;
|
@Inject SessionUtils sessionUtils;
|
||||||
@Inject RdapJsonFormatter rdapJsonFormatter;
|
@Inject RdapJsonFormatter rdapJsonFormatter;
|
||||||
|
@Inject @Parameter("registrar") Optional<String> registrarParam;
|
||||||
|
@Inject @Parameter("includeDeleted") Optional<Boolean> includeDeletedParam;
|
||||||
@Inject @Config("rdapLinkBase") String rdapLinkBase;
|
@Inject @Config("rdapLinkBase") String rdapLinkBase;
|
||||||
@Inject @Config("rdapWhoisServer") @Nullable String rdapWhoisServer;
|
@Inject @Config("rdapWhoisServer") @Nullable String rdapWhoisServer;
|
||||||
|
@Inject @Config("rdapResultSetMaxSize") int rdapResultSetMaxSize;
|
||||||
|
|
||||||
/** Returns a string like "domain name" or "nameserver", used for error strings. */
|
/** Returns a string like "domain name" or "nameserver", used for error strings. */
|
||||||
abstract String getHumanReadableObjectTypeName();
|
abstract String getHumanReadableObjectTypeName();
|
||||||
|
@ -169,6 +179,72 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
return RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, clientId);
|
return RdapAuthorization.create(RdapAuthorization.Role.REGISTRAR, clientId);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Returns the registrar on which results should be filtered, or absent(). */
|
||||||
|
Optional<String> getDesiredRegistrar() {
|
||||||
|
return registrarParam;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the query should include deleted items.
|
||||||
|
*
|
||||||
|
* <p>This is true only if the request specified an includeDeleted parameter of true, AND is
|
||||||
|
* eligible to see deleted information. Admins can see all deleted information, while
|
||||||
|
* authenticated registrars can see only their own deleted information. Note that if this method
|
||||||
|
* returns true, it just means that some deleted information might be viewable. If this is a
|
||||||
|
* registrar request, the caller must still verify that the registrar can see each particular
|
||||||
|
* item by calling {@link RdapAuthorization#isAuthorizedForClientId}.
|
||||||
|
*/
|
||||||
|
boolean shouldIncludeDeleted() {
|
||||||
|
// If includeDeleted is not specified, or set to false, we don't need to go any further.
|
||||||
|
if (!includeDeletedParam.or(false)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!authResult.userAuthInfo().isPresent()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
UserAuthInfo userAuthInfo = authResult.userAuthInfo().get();
|
||||||
|
if (userAuthInfo.isUserAdmin()) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (!sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
String clientId = sessionUtils.getRegistrarClientId(request);
|
||||||
|
checkState(
|
||||||
|
Registrar.loadByClientIdCached(clientId).isPresent(),
|
||||||
|
"Registrar with clientId %s doesn't exist",
|
||||||
|
clientId);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the EPP resource should be visible. This is true iff:
|
||||||
|
* 1. The resource is not deleted, or the request wants to see deleted items, and is authorized to
|
||||||
|
* do so, and:
|
||||||
|
* 2. The request did not specify a registrar to filter on, or the registrar matches.
|
||||||
|
*/
|
||||||
|
boolean shouldBeVisible(EppResource eppResource, DateTime now) {
|
||||||
|
return (now.isBefore(eppResource.getDeletionTime())
|
||||||
|
|| (shouldIncludeDeleted()
|
||||||
|
&& getAuthorization()
|
||||||
|
.isAuthorizedForClientId(eppResource.getPersistedCurrentSponsorClientId())))
|
||||||
|
&& (!registrarParam.isPresent()
|
||||||
|
|| registrarParam.get().equals(eppResource.getPersistedCurrentSponsorClientId()));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns true if the registrar should be visible. This is true iff:
|
||||||
|
* 1. The resource is active and publicly visible, or the request wants to see deleted items, and
|
||||||
|
* is authorized to do so, and:
|
||||||
|
* 2. The request did not specify a registrar to filter on, or the registrar matches.
|
||||||
|
*/
|
||||||
|
boolean shouldBeVisible(Registrar registrar) {
|
||||||
|
return (registrar.isActiveAndPubliclyVisible()
|
||||||
|
|| (shouldIncludeDeleted()
|
||||||
|
&& getAuthorization().isAuthorizedForClientId(registrar.getClientId())))
|
||||||
|
&& (!registrarParam.isPresent() || registrarParam.get().equals(registrar.getClientId()));
|
||||||
|
}
|
||||||
|
|
||||||
void validateDomainName(String name) {
|
void validateDomainName(String name) {
|
||||||
try {
|
try {
|
||||||
Optional<InternetDomainName> tld = findTldForName(InternetDomainName.from(name));
|
Optional<InternetDomainName> tld = findTldForName(InternetDomainName.from(name));
|
||||||
|
@ -190,10 +266,10 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handles prefix searches in cases where there are no pending deletes. In such cases, it is
|
* Handles prefix searches in cases where, if we need to filter out deleted items, there are no
|
||||||
* sufficient to check whether {@code deletionTime} is equal to {@code END_OF_TIME}, because any
|
* pending deletes. In such cases, it is sufficient to check whether {@code deletionTime} is equal
|
||||||
* other value means it has already been deleted. This allows us to use an equality query for the
|
* to {@code END_OF_TIME}, because any other value means it has already been deleted. This allows
|
||||||
* deletion time.
|
* us to use an equality query for the deletion time.
|
||||||
*
|
*
|
||||||
* @param clazz the type of resource to be queried
|
* @param clazz the type of resource to be queried
|
||||||
* @param filterField the database field of interest
|
* @param filterField the database field of interest
|
||||||
|
@ -201,13 +277,15 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
* equality query is used; if there is a wildcard, a range query is used instead; the
|
* equality query is used; if there is a wildcard, a range query is used instead; the
|
||||||
* initial string should not be empty, and any search suffix will be ignored, so the caller
|
* initial string should not be empty, and any search suffix will be ignored, so the caller
|
||||||
* must filter the results if a suffix is specified
|
* must filter the results if a suffix is specified
|
||||||
|
* @param includeDeleted whether to search for deleted items as well
|
||||||
* @param resultSetMaxSize the maximum number of results to return
|
* @param resultSetMaxSize the maximum number of results to return
|
||||||
* @return the results of the query
|
* @return the results of the query
|
||||||
*/
|
*/
|
||||||
static <T extends EppResource> Query<T> queryUndeleted(
|
static <T extends EppResource> Query<T> queryItems(
|
||||||
Class<T> clazz,
|
Class<T> clazz,
|
||||||
String filterField,
|
String filterField,
|
||||||
RdapSearchPattern partialStringQuery,
|
RdapSearchPattern partialStringQuery,
|
||||||
|
boolean includeDeleted,
|
||||||
int resultSetMaxSize) {
|
int resultSetMaxSize) {
|
||||||
if (partialStringQuery.getInitialString().length()
|
if (partialStringQuery.getInitialString().length()
|
||||||
< RdapSearchPattern.MIN_INITIAL_STRING_LENGTH) {
|
< RdapSearchPattern.MIN_INITIAL_STRING_LENGTH) {
|
||||||
|
@ -216,20 +294,125 @@ public abstract class RdapActionBase implements Runnable {
|
||||||
"Initial search string must be at least %d characters",
|
"Initial search string must be at least %d characters",
|
||||||
RdapSearchPattern.MIN_INITIAL_STRING_LENGTH));
|
RdapSearchPattern.MIN_INITIAL_STRING_LENGTH));
|
||||||
}
|
}
|
||||||
|
Query<T> query = ofy().load().type(clazz);
|
||||||
if (!partialStringQuery.getHasWildcard()) {
|
if (!partialStringQuery.getHasWildcard()) {
|
||||||
return ofy().load()
|
query = query.filter(filterField, partialStringQuery.getInitialString());
|
||||||
.type(clazz)
|
|
||||||
.filter(filterField, partialStringQuery.getInitialString())
|
|
||||||
.filter("deletionTime", END_OF_TIME)
|
|
||||||
.limit(resultSetMaxSize);
|
|
||||||
} else {
|
} else {
|
||||||
// Ignore the suffix; the caller will need to filter on the suffix, if any.
|
// Ignore the suffix; the caller will need to filter on the suffix, if any.
|
||||||
return ofy().load()
|
query = query
|
||||||
.type(clazz)
|
|
||||||
.filter(filterField + " >=", partialStringQuery.getInitialString())
|
.filter(filterField + " >=", partialStringQuery.getInitialString())
|
||||||
.filter(filterField + " <", partialStringQuery.getNextInitialString())
|
.filter(filterField + " <", partialStringQuery.getNextInitialString());
|
||||||
.filter("deletionTime", END_OF_TIME)
|
}
|
||||||
.limit(resultSetMaxSize);
|
if (!includeDeleted) {
|
||||||
|
query = query.filter("deletionTime", END_OF_TIME);
|
||||||
|
}
|
||||||
|
return query.limit(resultSetMaxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Variant of queryItems using a simple string rather than an {@link RdapSearchPattern}. */
|
||||||
|
static <T extends EppResource> Query<T> queryItems(
|
||||||
|
Class<T> clazz,
|
||||||
|
String filterField,
|
||||||
|
String queryString,
|
||||||
|
boolean includeDeleted,
|
||||||
|
int resultSetMaxSize) {
|
||||||
|
if (queryString.length() < RdapSearchPattern.MIN_INITIAL_STRING_LENGTH) {
|
||||||
|
throw new UnprocessableEntityException(
|
||||||
|
String.format(
|
||||||
|
"Initial search string must be at least %d characters",
|
||||||
|
RdapSearchPattern.MIN_INITIAL_STRING_LENGTH));
|
||||||
|
}
|
||||||
|
Query<T> query = ofy().load().type(clazz).filter(filterField, queryString);
|
||||||
|
return setOtherQueryAttributes(query, includeDeleted, resultSetMaxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Variant of queryItems where the field to be searched is the key. */
|
||||||
|
static <T extends EppResource> Query<T> queryItemsByKey(
|
||||||
|
Class<T> clazz,
|
||||||
|
RdapSearchPattern partialStringQuery,
|
||||||
|
boolean includeDeleted,
|
||||||
|
int resultSetMaxSize) {
|
||||||
|
if (partialStringQuery.getInitialString().length()
|
||||||
|
< RdapSearchPattern.MIN_INITIAL_STRING_LENGTH) {
|
||||||
|
throw new UnprocessableEntityException(
|
||||||
|
String.format(
|
||||||
|
"Initial search string must be at least %d characters",
|
||||||
|
RdapSearchPattern.MIN_INITIAL_STRING_LENGTH));
|
||||||
|
}
|
||||||
|
Query<T> query = ofy().load().type(clazz);
|
||||||
|
if (!partialStringQuery.getHasWildcard()) {
|
||||||
|
query = query.filterKey("=", Key.create(clazz, partialStringQuery.getInitialString()));
|
||||||
|
} else {
|
||||||
|
// Ignore the suffix; the caller will need to filter on the suffix, if any.
|
||||||
|
query = query
|
||||||
|
.filterKey(">=", Key.create(clazz, partialStringQuery.getInitialString()))
|
||||||
|
.filterKey("<", Key.create(clazz, partialStringQuery.getNextInitialString()));
|
||||||
|
}
|
||||||
|
return setOtherQueryAttributes(query, includeDeleted, resultSetMaxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Variant of queryItems searching for a key by a simple string. */
|
||||||
|
static <T extends EppResource> Query<T> queryItemsByKey(
|
||||||
|
Class<T> clazz,
|
||||||
|
String queryString,
|
||||||
|
boolean includeDeleted,
|
||||||
|
int resultSetMaxSize) {
|
||||||
|
if (queryString.length() < RdapSearchPattern.MIN_INITIAL_STRING_LENGTH) {
|
||||||
|
throw new UnprocessableEntityException(
|
||||||
|
String.format(
|
||||||
|
"Initial search string must be at least %d characters",
|
||||||
|
RdapSearchPattern.MIN_INITIAL_STRING_LENGTH));
|
||||||
|
}
|
||||||
|
Query<T> query = ofy().load().type(clazz).filterKey("=", Key.create(clazz, queryString));
|
||||||
|
return setOtherQueryAttributes(query, includeDeleted, resultSetMaxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static <T extends EppResource> Query<T> setOtherQueryAttributes(
|
||||||
|
Query<T> query, boolean includeDeleted, int resultSetMaxSize) {
|
||||||
|
if (!includeDeleted) {
|
||||||
|
query = query.filter("deletionTime", END_OF_TIME);
|
||||||
|
}
|
||||||
|
return query.limit(resultSetMaxSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs the given query, and checks for permissioning if necessary.
|
||||||
|
*
|
||||||
|
* @param query an already-defined query to be run; a filter on currentSponsorClientId will be
|
||||||
|
* added if appropriate
|
||||||
|
* @param now the time as of which to evaluate the query
|
||||||
|
* @return an {@link RdapResourcesAndIncompletenessWarningType} object containing the list of
|
||||||
|
* resources and an incompleteness warning flag, which is set to MIGHT_BE_INCOMPLETE iff
|
||||||
|
* any resources were excluded due to lack of visibility, and the resulting list of
|
||||||
|
* resources is less than the maximum allowable, which indicates that we may not have
|
||||||
|
* fetched enough resources
|
||||||
|
*/
|
||||||
|
<T extends EppResource> RdapResourcesAndIncompletenessWarningType<T> getMatchingResources(
|
||||||
|
Query<T> query, DateTime now) {
|
||||||
|
Optional<String> desiredRegistrar = getDesiredRegistrar();
|
||||||
|
if (desiredRegistrar.isPresent()) {
|
||||||
|
query = query.filter("currentSponsorClientId", desiredRegistrar.get());
|
||||||
|
}
|
||||||
|
if (!shouldIncludeDeleted()) {
|
||||||
|
return RdapResourcesAndIncompletenessWarningType.create(query.list());
|
||||||
|
}
|
||||||
|
// If we are including deleted resources, we need to check that we're authorized for each one.
|
||||||
|
List<T> resources = new ArrayList<>();
|
||||||
|
boolean someExcluded = false;
|
||||||
|
for (T resource : query) {
|
||||||
|
if (shouldBeVisible(resource, now)) {
|
||||||
|
resources.add(resource);
|
||||||
|
} else {
|
||||||
|
someExcluded = true;
|
||||||
|
}
|
||||||
|
if (resources.size() > rdapResultSetMaxSize) {
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return RdapResourcesAndIncompletenessWarningType.create(
|
||||||
|
resources,
|
||||||
|
(someExcluded && (resources.size() < rdapResultSetMaxSize + 1))
|
||||||
|
? IncompletenessWarningType.MIGHT_BE_INCOMPLETE
|
||||||
|
: IncompletenessWarningType.NONE);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,7 +29,6 @@ import com.google.common.collect.Iterables;
|
||||||
import com.google.common.primitives.Booleans;
|
import com.google.common.primitives.Booleans;
|
||||||
import com.googlecode.objectify.Key;
|
import com.googlecode.objectify.Key;
|
||||||
import com.googlecode.objectify.cmd.Query;
|
import com.googlecode.objectify.cmd.Query;
|
||||||
import google.registry.config.RegistryConfig.Config;
|
|
||||||
import google.registry.model.EppResourceUtils;
|
import google.registry.model.EppResourceUtils;
|
||||||
import google.registry.model.domain.DomainResource;
|
import google.registry.model.domain.DomainResource;
|
||||||
import google.registry.model.host.HostResource;
|
import google.registry.model.host.HostResource;
|
||||||
|
@ -81,7 +80,6 @@ public class RdapDomainSearchAction extends RdapActionBase {
|
||||||
@Inject @Parameter("name") Optional<String> nameParam;
|
@Inject @Parameter("name") Optional<String> nameParam;
|
||||||
@Inject @Parameter("nsLdhName") Optional<String> nsLdhNameParam;
|
@Inject @Parameter("nsLdhName") Optional<String> nsLdhNameParam;
|
||||||
@Inject @Parameter("nsIp") Optional<InetAddress> nsIpParam;
|
@Inject @Parameter("nsIp") Optional<InetAddress> nsIpParam;
|
||||||
@Inject @Config("rdapResultSetMaxSize") int rdapResultSetMaxSize;
|
|
||||||
@Inject RdapDomainSearchAction() {}
|
@Inject RdapDomainSearchAction() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -300,10 +298,11 @@ public class RdapDomainSearchAction extends RdapActionBase {
|
||||||
// Only return the first 1000 nameservers. This could result in an incomplete result set if
|
// Only return the first 1000 nameservers. This could result in an incomplete result set if
|
||||||
// a search asks for something like "ns*", but we need to enforce a limit in order to avoid
|
// a search asks for something like "ns*", but we need to enforce a limit in order to avoid
|
||||||
// arbitrarily long-running queries.
|
// arbitrarily long-running queries.
|
||||||
return queryUndeleted(
|
return queryItems(
|
||||||
HostResource.class,
|
HostResource.class,
|
||||||
"fullyQualifiedHostName",
|
"fullyQualifiedHostName",
|
||||||
partialStringQuery,
|
partialStringQuery,
|
||||||
|
false, /* includeDeleted */
|
||||||
MAX_NAMESERVERS_IN_FIRST_STAGE)
|
MAX_NAMESERVERS_IN_FIRST_STAGE)
|
||||||
.keys();
|
.keys();
|
||||||
}
|
}
|
||||||
|
|
|
@ -28,7 +28,6 @@ import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.primitives.Booleans;
|
import com.google.common.primitives.Booleans;
|
||||||
import com.google.common.primitives.Longs;
|
import com.google.common.primitives.Longs;
|
||||||
import com.googlecode.objectify.Key;
|
import com.googlecode.objectify.Key;
|
||||||
import google.registry.config.RegistryConfig.Config;
|
|
||||||
import google.registry.model.contact.ContactResource;
|
import google.registry.model.contact.ContactResource;
|
||||||
import google.registry.model.domain.DesignatedContact;
|
import google.registry.model.domain.DesignatedContact;
|
||||||
import google.registry.model.registrar.Registrar;
|
import google.registry.model.registrar.Registrar;
|
||||||
|
@ -69,7 +68,6 @@ public class RdapEntitySearchAction extends RdapActionBase {
|
||||||
@Inject Clock clock;
|
@Inject Clock clock;
|
||||||
@Inject @Parameter("fn") Optional<String> fnParam;
|
@Inject @Parameter("fn") Optional<String> fnParam;
|
||||||
@Inject @Parameter("handle") Optional<String> handleParam;
|
@Inject @Parameter("handle") Optional<String> handleParam;
|
||||||
@Inject @Config("rdapResultSetMaxSize") int rdapResultSetMaxSize;
|
|
||||||
@Inject RdapEntitySearchAction() {}
|
@Inject RdapEntitySearchAction() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -160,8 +158,13 @@ public class RdapEntitySearchAction extends RdapActionBase {
|
||||||
// Get the contact matches and return the results, fetching an additional contact to detect
|
// Get the contact matches and return the results, fetching an additional contact to detect
|
||||||
// truncation.
|
// truncation.
|
||||||
return makeSearchResults(
|
return makeSearchResults(
|
||||||
queryUndeleted(
|
queryItems(
|
||||||
ContactResource.class, "searchName", partialStringQuery, rdapResultSetMaxSize + 1).list(),
|
ContactResource.class,
|
||||||
|
"searchName",
|
||||||
|
partialStringQuery,
|
||||||
|
false /* includeDeleted */,
|
||||||
|
rdapResultSetMaxSize + 1)
|
||||||
|
.list(),
|
||||||
registrarMatches,
|
registrarMatches,
|
||||||
now);
|
now);
|
||||||
}
|
}
|
||||||
|
|
|
@ -23,6 +23,7 @@ import static google.registry.util.DomainNameUtils.ACE_PREFIX;
|
||||||
import com.google.common.base.Function;
|
import com.google.common.base.Function;
|
||||||
import com.google.common.base.Functions;
|
import com.google.common.base.Functions;
|
||||||
import com.google.common.base.Optional;
|
import com.google.common.base.Optional;
|
||||||
|
import com.google.common.base.Predicates;
|
||||||
import com.google.common.collect.FluentIterable;
|
import com.google.common.collect.FluentIterable;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
@ -172,8 +173,8 @@ public class RdapJsonFormatter {
|
||||||
private static final ImmutableMap<StatusValue, RdapStatus> statusToRdapStatusMap =
|
private static final ImmutableMap<StatusValue, RdapStatus> statusToRdapStatusMap =
|
||||||
Maps.immutableEnumMap(
|
Maps.immutableEnumMap(
|
||||||
new ImmutableMap.Builder<StatusValue, RdapStatus>()
|
new ImmutableMap.Builder<StatusValue, RdapStatus>()
|
||||||
// StatusValue.ADD_PERIOD not defined in our system
|
// RdapStatus.ADD_PERIOD not defined in our system
|
||||||
// StatusValue.AUTO_RENEW_PERIOD not defined in our system
|
// RdapStatus.AUTO_RENEW_PERIOD not defined in our system
|
||||||
.put(StatusValue.CLIENT_DELETE_PROHIBITED, RdapStatus.CLIENT_DELETE_PROHIBITED)
|
.put(StatusValue.CLIENT_DELETE_PROHIBITED, RdapStatus.CLIENT_DELETE_PROHIBITED)
|
||||||
.put(StatusValue.CLIENT_HOLD, RdapStatus.CLIENT_HOLD)
|
.put(StatusValue.CLIENT_HOLD, RdapStatus.CLIENT_HOLD)
|
||||||
.put(StatusValue.CLIENT_RENEW_PROHIBITED, RdapStatus.CLIENT_RENEW_PROHIBITED)
|
.put(StatusValue.CLIENT_RENEW_PROHIBITED, RdapStatus.CLIENT_RENEW_PROHIBITED)
|
||||||
|
@ -184,18 +185,18 @@ public class RdapJsonFormatter {
|
||||||
.put(StatusValue.OK, RdapStatus.ACTIVE)
|
.put(StatusValue.OK, RdapStatus.ACTIVE)
|
||||||
.put(StatusValue.PENDING_CREATE, RdapStatus.PENDING_CREATE)
|
.put(StatusValue.PENDING_CREATE, RdapStatus.PENDING_CREATE)
|
||||||
.put(StatusValue.PENDING_DELETE, RdapStatus.PENDING_DELETE)
|
.put(StatusValue.PENDING_DELETE, RdapStatus.PENDING_DELETE)
|
||||||
// StatusValue.PENDING_RENEW not defined in our system
|
// RdapStatus.PENDING_RENEW not defined in our system
|
||||||
// StatusValue.PENDING_RESTORE not defined in our system
|
// RdapStatus.PENDING_RESTORE not defined in our system
|
||||||
.put(StatusValue.PENDING_TRANSFER, RdapStatus.PENDING_TRANSFER)
|
.put(StatusValue.PENDING_TRANSFER, RdapStatus.PENDING_TRANSFER)
|
||||||
.put(StatusValue.PENDING_UPDATE, RdapStatus.PENDING_UPDATE)
|
.put(StatusValue.PENDING_UPDATE, RdapStatus.PENDING_UPDATE)
|
||||||
// StatusValue.REDEMPTION_PERIOD not defined in our system
|
// RdapStatus.REDEMPTION_PERIOD not defined in our system
|
||||||
// StatusValue.RENEW_PERIOD not defined in our system
|
// RdapStatus.RENEW_PERIOD not defined in our system
|
||||||
.put(StatusValue.SERVER_DELETE_PROHIBITED, RdapStatus.SERVER_DELETE_PROHIBITED)
|
.put(StatusValue.SERVER_DELETE_PROHIBITED, RdapStatus.SERVER_DELETE_PROHIBITED)
|
||||||
.put(StatusValue.SERVER_HOLD, RdapStatus.SERVER_HOLD)
|
.put(StatusValue.SERVER_HOLD, RdapStatus.SERVER_HOLD)
|
||||||
.put(StatusValue.SERVER_RENEW_PROHIBITED, RdapStatus.SERVER_RENEW_PROHIBITED)
|
.put(StatusValue.SERVER_RENEW_PROHIBITED, RdapStatus.SERVER_RENEW_PROHIBITED)
|
||||||
.put(StatusValue.SERVER_TRANSFER_PROHIBITED, RdapStatus.SERVER_TRANSFER_PROHIBITED)
|
.put(StatusValue.SERVER_TRANSFER_PROHIBITED, RdapStatus.SERVER_TRANSFER_PROHIBITED)
|
||||||
.put(StatusValue.SERVER_UPDATE_PROHIBITED, RdapStatus.SERVER_UPDATE_PROHIBITED)
|
.put(StatusValue.SERVER_UPDATE_PROHIBITED, RdapStatus.SERVER_UPDATE_PROHIBITED)
|
||||||
// StatusValue.TRANSFER_PERIOD not defined in our system
|
// RdapStatus.TRANSFER_PERIOD not defined in our system
|
||||||
.build());
|
.build());
|
||||||
|
|
||||||
/** Role values specified in RFC 7483 § 10.2.4. */
|
/** Role values specified in RFC 7483 § 10.2.4. */
|
||||||
|
@ -270,6 +271,8 @@ public class RdapJsonFormatter {
|
||||||
|
|
||||||
private static final ImmutableList<String> STATUS_LIST_ACTIVE =
|
private static final ImmutableList<String> STATUS_LIST_ACTIVE =
|
||||||
ImmutableList.of(RdapStatus.ACTIVE.rfc7483String);
|
ImmutableList.of(RdapStatus.ACTIVE.rfc7483String);
|
||||||
|
private static final ImmutableList<String> STATUS_LIST_REMOVED =
|
||||||
|
ImmutableList.of(RdapStatus.REMOVED.rfc7483String);
|
||||||
private static final ImmutableMap<String, ImmutableList<String>> PHONE_TYPE_VOICE =
|
private static final ImmutableMap<String, ImmutableList<String>> PHONE_TYPE_VOICE =
|
||||||
ImmutableMap.of("type", ImmutableList.of("voice"));
|
ImmutableMap.of("type", ImmutableList.of("voice"));
|
||||||
private static final ImmutableMap<String, ImmutableList<String>> PHONE_TYPE_FAX =
|
private static final ImmutableMap<String, ImmutableList<String>> PHONE_TYPE_FAX =
|
||||||
|
@ -464,7 +467,10 @@ public class RdapJsonFormatter {
|
||||||
if (hasUnicodeComponents(domainResource.getFullyQualifiedDomainName())) {
|
if (hasUnicodeComponents(domainResource.getFullyQualifiedDomainName())) {
|
||||||
jsonBuilder.put("unicodeName", Idn.toUnicode(domainResource.getFullyQualifiedDomainName()));
|
jsonBuilder.put("unicodeName", Idn.toUnicode(domainResource.getFullyQualifiedDomainName()));
|
||||||
}
|
}
|
||||||
jsonBuilder.put("status", makeStatusValueList(domainResource.getStatusValues()));
|
jsonBuilder.put(
|
||||||
|
"status",
|
||||||
|
makeStatusValueList(
|
||||||
|
domainResource.getStatusValues(), domainResource.getDeletionTime().isBefore(now)));
|
||||||
jsonBuilder.put("links", ImmutableList.of(
|
jsonBuilder.put("links", ImmutableList.of(
|
||||||
makeLink("domain", domainResource.getFullyQualifiedDomainName(), linkBase)));
|
makeLink("domain", domainResource.getFullyQualifiedDomainName(), linkBase)));
|
||||||
boolean displayContacts =
|
boolean displayContacts =
|
||||||
|
@ -577,7 +583,9 @@ public class RdapJsonFormatter {
|
||||||
.contains(StatusValue.PENDING_TRANSFER)) {
|
.contains(StatusValue.PENDING_TRANSFER)) {
|
||||||
statuses.add(StatusValue.PENDING_TRANSFER);
|
statuses.add(StatusValue.PENDING_TRANSFER);
|
||||||
}
|
}
|
||||||
jsonBuilder.put("status", makeStatusValueList(statuses.build()));
|
jsonBuilder.put(
|
||||||
|
"status",
|
||||||
|
makeStatusValueList(statuses.build(), hostResource.getDeletionTime().isBefore(now)));
|
||||||
jsonBuilder.put("links", ImmutableList.of(
|
jsonBuilder.put("links", ImmutableList.of(
|
||||||
makeLink("nameserver", hostResource.getFullyQualifiedHostName(), linkBase)));
|
makeLink("nameserver", hostResource.getFullyQualifiedHostName(), linkBase)));
|
||||||
List<ImmutableMap<String, Object>> remarks;
|
List<ImmutableMap<String, Object>> remarks;
|
||||||
|
@ -661,10 +669,13 @@ public class RdapJsonFormatter {
|
||||||
= new ImmutableList.Builder<>();
|
= new ImmutableList.Builder<>();
|
||||||
jsonBuilder.put("objectClassName", "entity");
|
jsonBuilder.put("objectClassName", "entity");
|
||||||
jsonBuilder.put("handle", contactResource.getRepoId());
|
jsonBuilder.put("handle", contactResource.getRepoId());
|
||||||
jsonBuilder.put("status", makeStatusValueList(
|
jsonBuilder.put(
|
||||||
|
"status",
|
||||||
|
makeStatusValueList(
|
||||||
isLinked(Key.create(contactResource), now)
|
isLinked(Key.create(contactResource), now)
|
||||||
? union(contactResource.getStatusValues(), StatusValue.LINKED)
|
? union(contactResource.getStatusValues(), StatusValue.LINKED)
|
||||||
: contactResource.getStatusValues()));
|
: contactResource.getStatusValues(),
|
||||||
|
contactResource.getDeletionTime().isBefore(now)));
|
||||||
if (contactType.isPresent()) {
|
if (contactType.isPresent()) {
|
||||||
jsonBuilder.put("roles",
|
jsonBuilder.put("roles",
|
||||||
ImmutableList.of(convertContactTypeToRdapRole(contactType.get())));
|
ImmutableList.of(convertContactTypeToRdapRole(contactType.get())));
|
||||||
|
@ -757,7 +768,7 @@ public class RdapJsonFormatter {
|
||||||
ImmutableMap.Builder<String, Object> jsonBuilder = new ImmutableMap.Builder<>();
|
ImmutableMap.Builder<String, Object> jsonBuilder = new ImmutableMap.Builder<>();
|
||||||
jsonBuilder.put("objectClassName", "entity");
|
jsonBuilder.put("objectClassName", "entity");
|
||||||
jsonBuilder.put("handle", registrar.getIanaIdentifier().toString());
|
jsonBuilder.put("handle", registrar.getIanaIdentifier().toString());
|
||||||
jsonBuilder.put("status", STATUS_LIST_ACTIVE);
|
jsonBuilder.put("status", registrar.isActive() ? STATUS_LIST_ACTIVE : STATUS_LIST_REMOVED);
|
||||||
jsonBuilder.put("roles", ImmutableList.of(RdapEntityRole.REGISTRAR.rfc7483String));
|
jsonBuilder.put("roles", ImmutableList.of(RdapEntityRole.REGISTRAR.rfc7483String));
|
||||||
jsonBuilder.put("links",
|
jsonBuilder.put("links",
|
||||||
ImmutableList.of(makeLink("entity", registrar.getIanaIdentifier().toString(), linkBase)));
|
ImmutableList.of(makeLink("entity", registrar.getIanaIdentifier().toString(), linkBase)));
|
||||||
|
@ -1045,18 +1056,30 @@ public class RdapJsonFormatter {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a string array of status values; the spec indicates that OK should be listed as
|
* Creates a string array of status values.
|
||||||
* "active".
|
*
|
||||||
|
* <p>The spec indicates that OK should be listed as "active". We use the "removed" status to
|
||||||
|
* indicate deleted objects.
|
||||||
*/
|
*/
|
||||||
private static ImmutableList<String> makeStatusValueList(ImmutableSet<StatusValue> statusValues) {
|
private static ImmutableList<String> makeStatusValueList(
|
||||||
return FluentIterable
|
ImmutableSet<StatusValue> statusValues, boolean isDeleted) {
|
||||||
.from(statusValues)
|
FluentIterable<RdapStatus> iterable =
|
||||||
.transform(Functions.forMap(statusToRdapStatusMap, RdapStatus.OBSCURED))
|
FluentIterable.from(statusValues)
|
||||||
.transform(new Function<RdapStatus, String>() {
|
.transform(Functions.forMap(statusToRdapStatusMap, RdapStatus.OBSCURED));
|
||||||
|
if (isDeleted) {
|
||||||
|
iterable =
|
||||||
|
iterable
|
||||||
|
.filter(Predicates.not(Predicates.equalTo(RdapStatus.ACTIVE)))
|
||||||
|
.append(RdapStatus.REMOVED);
|
||||||
|
}
|
||||||
|
return iterable
|
||||||
|
.transform(
|
||||||
|
new Function<RdapStatus, String>() {
|
||||||
@Override
|
@Override
|
||||||
public String apply(RdapStatus status) {
|
public String apply(RdapStatus status) {
|
||||||
return status.getDisplayName();
|
return status.getDisplayName();
|
||||||
}})
|
}
|
||||||
|
})
|
||||||
.toSortedSet(Ordering.natural())
|
.toSortedSet(Ordering.natural())
|
||||||
.asList();
|
.asList();
|
||||||
}
|
}
|
||||||
|
|
|
@ -61,4 +61,16 @@ public final class RdapModule {
|
||||||
static Optional<String> provideHandle(HttpServletRequest req) {
|
static Optional<String> provideHandle(HttpServletRequest req) {
|
||||||
return RequestParameters.extractOptionalParameter(req, "handle");
|
return RequestParameters.extractOptionalParameter(req, "handle");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Parameter("registrar")
|
||||||
|
static Optional<String> provideRegistrar(HttpServletRequest req) {
|
||||||
|
return RequestParameters.extractOptionalParameter(req, "registrar");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Parameter("includeDeleted")
|
||||||
|
static Optional<Boolean> provideIncludeDeleted(HttpServletRequest req) {
|
||||||
|
return RequestParameters.extractOptionalBooleanParameter(req, "includeDeleted");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,6 +17,7 @@ package google.registry.rdap;
|
||||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||||
import static google.registry.request.Action.Method.GET;
|
import static google.registry.request.Action.Method.GET;
|
||||||
import static google.registry.request.Action.Method.HEAD;
|
import static google.registry.request.Action.Method.HEAD;
|
||||||
|
import static google.registry.util.DateTimeUtils.START_OF_TIME;
|
||||||
|
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import google.registry.model.host.HostResource;
|
import google.registry.model.host.HostResource;
|
||||||
|
@ -59,8 +60,12 @@ public class RdapNameserverAction extends RdapActionBase {
|
||||||
pathSearchString = canonicalizeName(pathSearchString);
|
pathSearchString = canonicalizeName(pathSearchString);
|
||||||
// The RDAP syntax is /rdap/nameserver/ns1.mydomain.com.
|
// The RDAP syntax is /rdap/nameserver/ns1.mydomain.com.
|
||||||
validateDomainName(pathSearchString);
|
validateDomainName(pathSearchString);
|
||||||
HostResource hostResource = loadByForeignKey(HostResource.class, pathSearchString, now);
|
// If there are no undeleted nameservers with the given name, the foreign key should point to
|
||||||
if (hostResource == null) {
|
// the most recently deleted one.
|
||||||
|
HostResource hostResource =
|
||||||
|
loadByForeignKey(
|
||||||
|
HostResource.class, pathSearchString, shouldIncludeDeleted() ? START_OF_TIME : now);
|
||||||
|
if ((hostResource == null) || !shouldBeVisible(hostResource, now)) {
|
||||||
throw new NotFoundException(pathSearchString + " not found");
|
throw new NotFoundException(pathSearchString + " not found");
|
||||||
}
|
}
|
||||||
return rdapJsonFormatter.makeRdapJsonForHost(
|
return rdapJsonFormatter.makeRdapJsonForHost(
|
||||||
|
|
|
@ -15,10 +15,8 @@
|
||||||
package google.registry.rdap;
|
package google.registry.rdap;
|
||||||
|
|
||||||
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
import static google.registry.model.EppResourceUtils.loadByForeignKey;
|
||||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
|
||||||
import static google.registry.request.Action.Method.GET;
|
import static google.registry.request.Action.Method.GET;
|
||||||
import static google.registry.request.Action.Method.HEAD;
|
import static google.registry.request.Action.Method.HEAD;
|
||||||
import static google.registry.util.DateTimeUtils.END_OF_TIME;
|
|
||||||
|
|
||||||
import com.google.common.base.Optional;
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
@ -26,7 +24,7 @@ import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSortedSet;
|
import com.google.common.collect.ImmutableSortedSet;
|
||||||
import com.google.common.collect.Iterables;
|
import com.google.common.collect.Iterables;
|
||||||
import com.google.common.primitives.Booleans;
|
import com.google.common.primitives.Booleans;
|
||||||
import google.registry.config.RegistryConfig.Config;
|
import com.googlecode.objectify.cmd.Query;
|
||||||
import google.registry.model.domain.DomainResource;
|
import google.registry.model.domain.DomainResource;
|
||||||
import google.registry.model.host.HostResource;
|
import google.registry.model.host.HostResource;
|
||||||
import google.registry.rdap.RdapJsonFormatter.BoilerplateType;
|
import google.registry.rdap.RdapJsonFormatter.BoilerplateType;
|
||||||
|
@ -64,11 +62,11 @@ import org.joda.time.DateTime;
|
||||||
public class RdapNameserverSearchAction extends RdapActionBase {
|
public class RdapNameserverSearchAction extends RdapActionBase {
|
||||||
|
|
||||||
public static final String PATH = "/rdap/nameservers";
|
public static final String PATH = "/rdap/nameservers";
|
||||||
|
private static final int RESULT_SET_SIZE_SCALING_FACTOR = 30;
|
||||||
|
|
||||||
@Inject Clock clock;
|
@Inject Clock clock;
|
||||||
@Inject @Parameter("name") Optional<String> nameParam;
|
@Inject @Parameter("name") Optional<String> nameParam;
|
||||||
@Inject @Parameter("ip") Optional<InetAddress> ipParam;
|
@Inject @Parameter("ip") Optional<InetAddress> ipParam;
|
||||||
@Inject @Config("rdapResultSetMaxSize") int rdapResultSetMaxSize;
|
|
||||||
@Inject RdapNameserverSearchAction() {}
|
@Inject RdapNameserverSearchAction() {}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -125,26 +123,57 @@ public class RdapNameserverSearchAction extends RdapActionBase {
|
||||||
return jsonBuilder.build();
|
return jsonBuilder.build();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Searches for nameservers by name, returning a JSON array of nameserver info maps. */
|
/**
|
||||||
|
* Searches for nameservers by name, returning a JSON array of nameserver info maps.
|
||||||
|
*
|
||||||
|
* <p>When deleted nameservers are included in the search, the search is treated as if it has a
|
||||||
|
* wildcard, because multiple results can be returned.
|
||||||
|
*/
|
||||||
private RdapSearchResults searchByName(
|
private RdapSearchResults searchByName(
|
||||||
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||||
// Handle queries without a wildcard -- just load by foreign key.
|
// Handle queries without a wildcard -- just load by foreign key. We can't do this if deleted
|
||||||
if (!partialStringQuery.getHasWildcard()) {
|
// nameservers are desired, because there may be multiple nameservers with the same name.
|
||||||
|
if (!partialStringQuery.getHasWildcard() && !shouldIncludeDeleted()) {
|
||||||
|
return searchByNameUsingForeignKey(partialStringQuery, now);
|
||||||
|
// Handle queries with a wildcard (or including deleted entries). If there is a suffix, it
|
||||||
|
// should be a domain that we manage, so we can look up the domain and search through the
|
||||||
|
// subordinate hosts. This is more efficient, and lets us permit wildcard searches with no
|
||||||
|
// initial string. Deleted nameservers cannot be searched using a suffix, because the logic
|
||||||
|
// of the deletion status of the superordinate domain versus the deletion status of the
|
||||||
|
// subordinate host gets too messy.
|
||||||
|
} else if (partialStringQuery.getSuffix() != null) {
|
||||||
|
if (shouldIncludeDeleted()) {
|
||||||
|
throw new UnprocessableEntityException(
|
||||||
|
"A suffix after a wildcard is not allowed when searching for deleted nameservers");
|
||||||
|
}
|
||||||
|
return searchByNameUsingSuperordinateDomain(partialStringQuery, now);
|
||||||
|
// Handle queries with a wildcard (or deleted entries included), but no suffix.
|
||||||
|
} else {
|
||||||
|
return searchByNameUsingPrefix(partialStringQuery, now);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Searches for nameservers by name with no wildcard or deleted names.
|
||||||
|
*
|
||||||
|
* <p>In this case, we can load by foreign key.
|
||||||
|
*/
|
||||||
|
private RdapSearchResults searchByNameUsingForeignKey(
|
||||||
|
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||||
HostResource hostResource =
|
HostResource hostResource =
|
||||||
loadByForeignKey(HostResource.class, partialStringQuery.getInitialString(), now);
|
loadByForeignKey(HostResource.class, partialStringQuery.getInitialString(), now);
|
||||||
if (hostResource == null) {
|
if ((hostResource == null) || !shouldBeVisible(hostResource, now)) {
|
||||||
throw new NotFoundException("No nameservers found");
|
throw new NotFoundException("No nameservers found");
|
||||||
}
|
}
|
||||||
return RdapSearchResults.create(
|
return RdapSearchResults.create(
|
||||||
ImmutableList.of(
|
ImmutableList.of(
|
||||||
rdapJsonFormatter.makeRdapJsonForHost(
|
rdapJsonFormatter.makeRdapJsonForHost(
|
||||||
hostResource, false, rdapLinkBase, rdapWhoisServer, now, OutputDataType.FULL)));
|
hostResource, false, rdapLinkBase, rdapWhoisServer, now, OutputDataType.FULL)));
|
||||||
// Handle queries with a wildcard.
|
}
|
||||||
} else {
|
|
||||||
// If there is a suffix, it should be a domain that we manage, so we can look up the domain
|
/** Searches for nameservers by name using the superordinate domain as a suffix. */
|
||||||
// and search through the subordinate hosts. This is more efficient, and lets us permit
|
private RdapSearchResults searchByNameUsingSuperordinateDomain(
|
||||||
// wildcard searches with no initial string.
|
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||||
if (partialStringQuery.getSuffix() != null) {
|
|
||||||
DomainResource domainResource =
|
DomainResource domainResource =
|
||||||
loadByForeignKey(DomainResource.class, partialStringQuery.getSuffix(), now);
|
loadByForeignKey(DomainResource.class, partialStringQuery.getSuffix(), now);
|
||||||
if (domainResource == null) {
|
if (domainResource == null) {
|
||||||
|
@ -162,7 +191,7 @@ public class RdapNameserverSearchAction extends RdapActionBase {
|
||||||
// then the query ns.exam*.example.com would match against nameserver ns.example.com.
|
// then the query ns.exam*.example.com would match against nameserver ns.example.com.
|
||||||
if (partialStringQuery.matches(fqhn)) {
|
if (partialStringQuery.matches(fqhn)) {
|
||||||
HostResource hostResource = loadByForeignKey(HostResource.class, fqhn, now);
|
HostResource hostResource = loadByForeignKey(HostResource.class, fqhn, now);
|
||||||
if (hostResource != null) {
|
if ((hostResource != null) && shouldBeVisible(hostResource, now)) {
|
||||||
hostList.add(hostResource);
|
hostList.add(hostResource);
|
||||||
if (hostList.size() > rdapResultSetMaxSize) {
|
if (hostList.size() > rdapResultSetMaxSize) {
|
||||||
break;
|
break;
|
||||||
|
@ -170,40 +199,60 @@ public class RdapNameserverSearchAction extends RdapActionBase {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return makeSearchResults(hostList, now);
|
return makeSearchResults(hostList, IncompletenessWarningType.NONE, now);
|
||||||
// Handle queries with a wildcard, but no suffix. There are no pending deletes for hosts, so
|
}
|
||||||
// we can call queryUndeleted. Unlike the above problem with suffixes, we can safely search
|
|
||||||
// for nameservers beginning with a particular suffix, because we need only fetch the first
|
/**
|
||||||
// rdapResultSetMaxSize entries, and ignore the rest.
|
* Searches for nameservers by name with a prefix and wildcard.
|
||||||
} else {
|
*
|
||||||
return makeSearchResults(
|
* <p>There are no pending deletes for hosts, so we can call {@link RdapActionBase#queryItems}.
|
||||||
|
*/
|
||||||
|
private RdapSearchResults searchByNameUsingPrefix(
|
||||||
|
final RdapSearchPattern partialStringQuery, final DateTime now) {
|
||||||
// Add 1 so we can detect truncation.
|
// Add 1 so we can detect truncation.
|
||||||
queryUndeleted(
|
Query<HostResource> query =
|
||||||
|
queryItems(
|
||||||
HostResource.class,
|
HostResource.class,
|
||||||
"fullyQualifiedHostName",
|
"fullyQualifiedHostName",
|
||||||
partialStringQuery,
|
partialStringQuery,
|
||||||
rdapResultSetMaxSize + 1)
|
shouldIncludeDeleted(),
|
||||||
.list(),
|
shouldIncludeDeleted()
|
||||||
now);
|
? (RESULT_SET_SIZE_SCALING_FACTOR * (rdapResultSetMaxSize + 1))
|
||||||
}
|
: (rdapResultSetMaxSize + 1));
|
||||||
}
|
return makeSearchResults(getMatchingResources(query, now), now);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Searches for nameservers by IP address, returning a JSON array of nameserver info maps. */
|
/** Searches for nameservers by IP address, returning a JSON array of nameserver info maps. */
|
||||||
private RdapSearchResults searchByIp(final InetAddress inetAddress, DateTime now) {
|
private RdapSearchResults searchByIp(final InetAddress inetAddress, DateTime now) {
|
||||||
return makeSearchResults(
|
|
||||||
// Add 1 so we can detect truncation.
|
// Add 1 so we can detect truncation.
|
||||||
ofy().load()
|
Query<HostResource> query =
|
||||||
.type(HostResource.class)
|
queryItems(
|
||||||
.filter("inetAddresses", inetAddress.getHostAddress())
|
HostResource.class,
|
||||||
.filter("deletionTime", END_OF_TIME)
|
"inetAddresses",
|
||||||
.limit(rdapResultSetMaxSize + 1)
|
inetAddress.getHostAddress(),
|
||||||
.list(),
|
shouldIncludeDeleted(),
|
||||||
|
shouldIncludeDeleted()
|
||||||
|
? (RESULT_SET_SIZE_SCALING_FACTOR * (rdapResultSetMaxSize + 1))
|
||||||
|
: (rdapResultSetMaxSize + 1));
|
||||||
|
return makeSearchResults(getMatchingResources(query, now), now);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Output JSON for a lists of hosts contained in an {@link
|
||||||
|
* RdapResourcesAndIncompletenessWarningType}.
|
||||||
|
*/
|
||||||
|
private RdapSearchResults makeSearchResults(
|
||||||
|
RdapResourcesAndIncompletenessWarningType<HostResource> resourcesAndIncompletenessWarningType,
|
||||||
|
DateTime now) {
|
||||||
|
return makeSearchResults(
|
||||||
|
resourcesAndIncompletenessWarningType.resources(),
|
||||||
|
resourcesAndIncompletenessWarningType.incompletenessWarningType(),
|
||||||
now);
|
now);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Output JSON for a list of hosts. */
|
/** Output JSON for a list of hosts. */
|
||||||
private RdapSearchResults makeSearchResults(List<HostResource> hosts, DateTime now) {
|
private RdapSearchResults makeSearchResults(
|
||||||
|
List<HostResource> hosts, IncompletenessWarningType incompletenessWarningType, DateTime now) {
|
||||||
OutputDataType outputDataType =
|
OutputDataType outputDataType =
|
||||||
(hosts.size() > 1) ? OutputDataType.SUMMARY : OutputDataType.FULL;
|
(hosts.size() > 1) ? OutputDataType.SUMMARY : OutputDataType.FULL;
|
||||||
ImmutableList.Builder<ImmutableMap<String, Object>> jsonListBuilder =
|
ImmutableList.Builder<ImmutableMap<String, Object>> jsonListBuilder =
|
||||||
|
@ -218,6 +267,6 @@ public class RdapNameserverSearchAction extends RdapActionBase {
|
||||||
jsonList,
|
jsonList,
|
||||||
(jsonList.size() < hosts.size())
|
(jsonList.size() < hosts.size())
|
||||||
? IncompletenessWarningType.TRUNCATED
|
? IncompletenessWarningType.TRUNCATED
|
||||||
: IncompletenessWarningType.NONE);
|
: incompletenessWarningType);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,42 @@
|
||||||
|
// 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.rdap;
|
||||||
|
|
||||||
|
import com.google.auto.value.AutoValue;
|
||||||
|
import google.registry.model.EppResource;
|
||||||
|
import google.registry.rdap.RdapSearchResults.IncompletenessWarningType;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
@AutoValue
|
||||||
|
abstract class RdapResourcesAndIncompletenessWarningType<T extends EppResource> {
|
||||||
|
|
||||||
|
static <S extends EppResource> RdapResourcesAndIncompletenessWarningType<S> create(
|
||||||
|
List<S> resources) {
|
||||||
|
return create(resources, IncompletenessWarningType.NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
static <S extends EppResource> RdapResourcesAndIncompletenessWarningType<S> create(
|
||||||
|
List<S> resources, IncompletenessWarningType incompletenessWarningType) {
|
||||||
|
return new AutoValue_RdapResourcesAndIncompletenessWarningType<S>(
|
||||||
|
resources, incompletenessWarningType);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** List of EPP resources. */
|
||||||
|
abstract List<T> resources();
|
||||||
|
|
||||||
|
/** Type of warning to display regarding possible incomplete data. */
|
||||||
|
abstract IncompletenessWarningType incompletenessWarningType();
|
||||||
|
}
|
||||||
|
|
|
@ -16,20 +16,31 @@ package google.registry.rdap;
|
||||||
|
|
||||||
import static com.google.common.truth.Truth.assertThat;
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
import static google.registry.testing.DatastoreHelper.createTld;
|
import static google.registry.testing.DatastoreHelper.createTld;
|
||||||
|
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeAndPersistHostResource;
|
import static google.registry.testing.FullFieldsTestEntityHelper.makeAndPersistHostResource;
|
||||||
|
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
|
||||||
import static google.registry.testing.TestDataHelper.loadFileWithSubstitutions;
|
import static google.registry.testing.TestDataHelper.loadFileWithSubstitutions;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
import com.google.appengine.api.NamespaceManager;
|
import com.google.appengine.api.users.User;
|
||||||
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import com.google.common.collect.ImmutableSet;
|
import com.google.common.collect.ImmutableSet;
|
||||||
import google.registry.model.ofy.Ofy;
|
import google.registry.model.ofy.Ofy;
|
||||||
|
import google.registry.model.registrar.Registrar;
|
||||||
|
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.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
|
import google.registry.ui.server.registrar.SessionUtils;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.json.simple.JSONValue;
|
import org.json.simple.JSONValue;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -50,8 +61,13 @@ public class RdapNameserverActionTest {
|
||||||
@Rule
|
@Rule
|
||||||
public final InjectRule inject = new InjectRule();
|
public final InjectRule inject = new InjectRule();
|
||||||
|
|
||||||
|
private final HttpServletRequest request = mock(HttpServletRequest.class);
|
||||||
private final FakeResponse response = new FakeResponse();
|
private final FakeResponse response = new FakeResponse();
|
||||||
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 User user = new User("rdap.user@example.com", "gmail.com", "12345");
|
||||||
|
private final UserAuthInfo userAuthInfo = UserAuthInfo.create(user, false);
|
||||||
|
private final UserAuthInfo adminUserAuthInfo = UserAuthInfo.create(user, true);
|
||||||
|
|
||||||
@Before
|
@Before
|
||||||
public void setUp() throws Exception {
|
public void setUp() throws Exception {
|
||||||
|
@ -68,22 +84,50 @@ public class RdapNameserverActionTest {
|
||||||
createTld("1.tld");
|
createTld("1.tld");
|
||||||
makeAndPersistHostResource(
|
makeAndPersistHostResource(
|
||||||
"ns1.domain.1.tld", "5.6.7.8", clock.nowUtc().minusYears(1));
|
"ns1.domain.1.tld", "5.6.7.8", clock.nowUtc().minusYears(1));
|
||||||
NamespaceManager.set(null);
|
// deleted
|
||||||
|
persistResource(
|
||||||
|
makeAndPersistHostResource("nsdeleted.cat.lol", "1.2.3.4", clock.nowUtc().minusYears(1))
|
||||||
|
.asBuilder()
|
||||||
|
.setDeletionTime(clock.nowUtc().minusMonths(1))
|
||||||
|
.build());
|
||||||
|
// other registrar
|
||||||
|
persistResource(
|
||||||
|
makeRegistrar("otherregistrar", "Yes Virginia <script>", Registrar.State.ACTIVE, 102L));
|
||||||
}
|
}
|
||||||
|
|
||||||
private RdapNameserverAction newRdapNameserverAction(String input) {
|
private RdapNameserverAction newRdapNameserverAction(
|
||||||
|
String input, Optional<String> desiredRegistrar, Optional<Boolean> includeDeleted) {
|
||||||
|
return newRdapNameserverAction(
|
||||||
|
input, desiredRegistrar, includeDeleted, AuthResult.create(AuthLevel.USER, userAuthInfo));
|
||||||
|
}
|
||||||
|
|
||||||
|
private RdapNameserverAction newRdapNameserverAction(
|
||||||
|
String input,
|
||||||
|
Optional<String> desiredRegistrar,
|
||||||
|
Optional<Boolean> includeDeleted,
|
||||||
|
AuthResult authResult) {
|
||||||
RdapNameserverAction action = new RdapNameserverAction();
|
RdapNameserverAction action = new RdapNameserverAction();
|
||||||
action.clock = clock;
|
action.clock = clock;
|
||||||
|
action.request = request;
|
||||||
action.response = response;
|
action.response = response;
|
||||||
action.requestPath = RdapNameserverAction.PATH.concat(input);
|
action.requestPath = RdapNameserverAction.PATH.concat(input);
|
||||||
|
action.registrarParam = desiredRegistrar;
|
||||||
|
action.includeDeletedParam = includeDeleted;
|
||||||
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
||||||
action.rdapLinkBase = "https://example.tld/rdap/";
|
action.rdapLinkBase = "https://example.tld/rdap/";
|
||||||
action.rdapWhoisServer = null;
|
action.rdapWhoisServer = null;
|
||||||
|
action.authResult = authResult;
|
||||||
|
action.sessionUtils = sessionUtils;
|
||||||
return action;
|
return action;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object generateActualJson(String name) {
|
private Object generateActualJson(String name) {
|
||||||
newRdapNameserverAction(name).run();
|
return generateActualJson(name, Optional.<String>absent(), Optional.<Boolean>absent());
|
||||||
|
}
|
||||||
|
|
||||||
|
private Object generateActualJson(
|
||||||
|
String name, Optional<String> desiredRegistrar, Optional<Boolean> includeDeleted) {
|
||||||
|
newRdapNameserverAction(name, desiredRegistrar, includeDeleted).run();
|
||||||
return JSONValue.parse(response.getPayload());
|
return JSONValue.parse(response.getPayload());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -153,7 +197,11 @@ public class RdapNameserverActionTest {
|
||||||
assertThat(generateActualJson("ns1.cat.lol"))
|
assertThat(generateActualJson("ns1.cat.lol"))
|
||||||
.isEqualTo(generateExpectedJsonWithTopLevelEntries(
|
.isEqualTo(generateExpectedJsonWithTopLevelEntries(
|
||||||
"ns1.cat.lol",
|
"ns1.cat.lol",
|
||||||
ImmutableMap.of("HANDLE", "2-ROID", "ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4"),
|
ImmutableMap.of(
|
||||||
|
"HANDLE", "2-ROID",
|
||||||
|
"ADDRESSTYPE", "v4",
|
||||||
|
"ADDRESS", "1.2.3.4",
|
||||||
|
"STATUS", "active"),
|
||||||
"rdap_host.json"));
|
"rdap_host.json"));
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
@ -163,7 +211,11 @@ public class RdapNameserverActionTest {
|
||||||
assertThat(generateActualJson("ns1.cat.lol."))
|
assertThat(generateActualJson("ns1.cat.lol."))
|
||||||
.isEqualTo(generateExpectedJsonWithTopLevelEntries(
|
.isEqualTo(generateExpectedJsonWithTopLevelEntries(
|
||||||
"ns1.cat.lol",
|
"ns1.cat.lol",
|
||||||
ImmutableMap.of("HANDLE", "2-ROID", "ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4"),
|
ImmutableMap.of(
|
||||||
|
"HANDLE", "2-ROID",
|
||||||
|
"ADDRESSTYPE", "v4",
|
||||||
|
"ADDRESS", "1.2.3.4",
|
||||||
|
"STATUS", "active"),
|
||||||
"rdap_host.json"));
|
"rdap_host.json"));
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
@ -173,7 +225,11 @@ public class RdapNameserverActionTest {
|
||||||
assertThat(generateActualJson("ns1.cat.lol?key=value"))
|
assertThat(generateActualJson("ns1.cat.lol?key=value"))
|
||||||
.isEqualTo(generateExpectedJsonWithTopLevelEntries(
|
.isEqualTo(generateExpectedJsonWithTopLevelEntries(
|
||||||
"ns1.cat.lol",
|
"ns1.cat.lol",
|
||||||
ImmutableMap.of("HANDLE", "2-ROID", "ADDRESSTYPE", "v4", "ADDRESS", "1.2.3.4"),
|
ImmutableMap.of(
|
||||||
|
"HANDLE", "2-ROID",
|
||||||
|
"ADDRESSTYPE", "v4",
|
||||||
|
"ADDRESS", "1.2.3.4",
|
||||||
|
"STATUS", "active"),
|
||||||
"rdap_host.json"));
|
"rdap_host.json"));
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
@ -187,7 +243,8 @@ public class RdapNameserverActionTest {
|
||||||
"PUNYCODENAME", "ns1.cat.xn--q9jyb4c",
|
"PUNYCODENAME", "ns1.cat.xn--q9jyb4c",
|
||||||
"HANDLE", "5-ROID",
|
"HANDLE", "5-ROID",
|
||||||
"ADDRESSTYPE", "v6",
|
"ADDRESSTYPE", "v6",
|
||||||
"ADDRESS", "bad:f00d:cafe::15:beef"),
|
"ADDRESS", "bad:f00d:cafe::15:beef",
|
||||||
|
"STATUS", "active"),
|
||||||
"rdap_host_unicode.json"));
|
"rdap_host_unicode.json"));
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
@ -201,7 +258,8 @@ public class RdapNameserverActionTest {
|
||||||
"PUNYCODENAME", "ns1.cat.xn--q9jyb4c",
|
"PUNYCODENAME", "ns1.cat.xn--q9jyb4c",
|
||||||
"HANDLE", "5-ROID",
|
"HANDLE", "5-ROID",
|
||||||
"ADDRESSTYPE", "v6",
|
"ADDRESSTYPE", "v6",
|
||||||
"ADDRESS", "bad:f00d:cafe::15:beef"),
|
"ADDRESS", "bad:f00d:cafe::15:beef",
|
||||||
|
"STATUS", "active"),
|
||||||
"rdap_host_unicode.json"));
|
"rdap_host_unicode.json"));
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
@ -211,8 +269,129 @@ public class RdapNameserverActionTest {
|
||||||
assertThat(generateActualJson("ns1.domain.1.tld"))
|
assertThat(generateActualJson("ns1.domain.1.tld"))
|
||||||
.isEqualTo(generateExpectedJsonWithTopLevelEntries(
|
.isEqualTo(generateExpectedJsonWithTopLevelEntries(
|
||||||
"ns1.domain.1.tld",
|
"ns1.domain.1.tld",
|
||||||
ImmutableMap.of("HANDLE", "8-ROID", "ADDRESSTYPE", "v4", "ADDRESS", "5.6.7.8"),
|
ImmutableMap.of(
|
||||||
|
"HANDLE", "8-ROID",
|
||||||
|
"ADDRESSTYPE", "v4",
|
||||||
|
"ADDRESS", "5.6.7.8",
|
||||||
|
"STATUS", "active"),
|
||||||
"rdap_host.json"));
|
"rdap_host.json"));
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameserver_found_sameRegistrarRequested() throws Exception {
|
||||||
|
assertThat(
|
||||||
|
generateActualJson(
|
||||||
|
"ns1.cat.lol", Optional.of("TheRegistrar"), Optional.<Boolean>absent()))
|
||||||
|
.isEqualTo(
|
||||||
|
generateExpectedJsonWithTopLevelEntries(
|
||||||
|
"ns1.cat.lol",
|
||||||
|
ImmutableMap.of(
|
||||||
|
"HANDLE", "2-ROID",
|
||||||
|
"ADDRESSTYPE", "v4",
|
||||||
|
"ADDRESS", "1.2.3.4",
|
||||||
|
"STATUS", "active"),
|
||||||
|
"rdap_host.json"));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameserver_notFound_differentRegistrarRequested() throws Exception {
|
||||||
|
generateActualJson("ns1.cat.lol", Optional.of("otherregistrar"), Optional.of(false));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletedNameserver_notFound_includeDeletedNotSpecified() throws Exception {
|
||||||
|
generateActualJson("nsdeleted.cat.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletedNameserver_notFound_includeDeletedSetFalse() throws Exception {
|
||||||
|
generateActualJson("nsdeleted.cat.lol", Optional.<String>absent(), Optional.of(false));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletedNameserver_notFound_notLoggedIn() throws Exception {
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(false);
|
||||||
|
generateActualJson("nsdeleted.cat.lol", Optional.<String>absent(), Optional.of(true));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletedNameserver_notFound_loggedInAsDifferentRegistrar() throws Exception {
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("otherregistrar");
|
||||||
|
generateActualJson("nsdeleted.cat.lol", Optional.<String>absent(), Optional.of(true));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletedNameserver_found_loggedInAsCorrectRegistrar() throws Exception {
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("TheRegistrar");
|
||||||
|
assertThat(
|
||||||
|
generateActualJson("nsdeleted.cat.lol", Optional.<String>absent(), Optional.of(true)))
|
||||||
|
.isEqualTo(
|
||||||
|
generateExpectedJsonWithTopLevelEntries(
|
||||||
|
"nsdeleted.cat.lol",
|
||||||
|
ImmutableMap.of(
|
||||||
|
"HANDLE", "A-ROID",
|
||||||
|
"ADDRESSTYPE", "v4",
|
||||||
|
"ADDRESS", "1.2.3.4",
|
||||||
|
"STATUS", "removed"),
|
||||||
|
"rdap_host.json"));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletedNameserver_found_loggedInAsAdmin() throws Exception {
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, adminUserAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("irrelevant");
|
||||||
|
newRdapNameserverAction(
|
||||||
|
"nsdeleted.cat.lol",
|
||||||
|
Optional.<String>absent(),
|
||||||
|
Optional.of(true),
|
||||||
|
AuthResult.create(AuthLevel.USER, adminUserAuthInfo))
|
||||||
|
.run();
|
||||||
|
assertThat(JSONValue.parse(response.getPayload()))
|
||||||
|
.isEqualTo(
|
||||||
|
generateExpectedJsonWithTopLevelEntries(
|
||||||
|
"nsdeleted.cat.lol",
|
||||||
|
ImmutableMap.of(
|
||||||
|
"HANDLE", "A-ROID",
|
||||||
|
"ADDRESSTYPE", "v4",
|
||||||
|
"ADDRESS", "1.2.3.4",
|
||||||
|
"STATUS", "removed"),
|
||||||
|
"rdap_host.json"));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletedNameserver_found_sameRegistrarRequested() throws Exception {
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("TheRegistrar");
|
||||||
|
assertThat(
|
||||||
|
generateActualJson("nsdeleted.cat.lol", Optional.of("TheRegistrar"), Optional.of(true)))
|
||||||
|
.isEqualTo(
|
||||||
|
generateExpectedJsonWithTopLevelEntries(
|
||||||
|
"nsdeleted.cat.lol",
|
||||||
|
ImmutableMap.of(
|
||||||
|
"HANDLE", "A-ROID",
|
||||||
|
"ADDRESSTYPE", "v4",
|
||||||
|
"ADDRESS", "1.2.3.4",
|
||||||
|
"STATUS", "removed"),
|
||||||
|
"rdap_host.json"));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testDeletedNameserver_notFound_differentRegistrarRequested() throws Exception {
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("TheRegistrar");
|
||||||
|
generateActualJson("ns1.cat.lol", Optional.of("otherregistrar"), Optional.of(false));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -26,7 +26,10 @@ import static google.registry.testing.FullFieldsTestEntityHelper.makeHostResourc
|
||||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
|
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrar;
|
||||||
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrarContacts;
|
import static google.registry.testing.FullFieldsTestEntityHelper.makeRegistrarContacts;
|
||||||
import static google.registry.testing.TestDataHelper.loadFileWithSubstitutions;
|
import static google.registry.testing.TestDataHelper.loadFileWithSubstitutions;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
import com.google.appengine.api.users.User;
|
||||||
import com.google.common.base.Optional;
|
import com.google.common.base.Optional;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
@ -37,11 +40,16 @@ import google.registry.model.domain.DomainResource;
|
||||||
import google.registry.model.host.HostResource;
|
import google.registry.model.host.HostResource;
|
||||||
import google.registry.model.ofy.Ofy;
|
import google.registry.model.ofy.Ofy;
|
||||||
import google.registry.model.registrar.Registrar;
|
import google.registry.model.registrar.Registrar;
|
||||||
|
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.FakeResponse;
|
import google.registry.testing.FakeResponse;
|
||||||
import google.registry.testing.InjectRule;
|
import google.registry.testing.InjectRule;
|
||||||
|
import google.registry.ui.server.registrar.SessionUtils;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
|
import javax.servlet.http.HttpServletRequest;
|
||||||
import org.joda.time.DateTime;
|
import org.joda.time.DateTime;
|
||||||
import org.json.simple.JSONValue;
|
import org.json.simple.JSONValue;
|
||||||
import org.junit.Before;
|
import org.junit.Before;
|
||||||
|
@ -58,9 +66,13 @@ public class RdapNameserverSearchActionTest {
|
||||||
|
|
||||||
@Rule public final InjectRule inject = new InjectRule();
|
@Rule public final InjectRule inject = new InjectRule();
|
||||||
|
|
||||||
|
private final HttpServletRequest request = mock(HttpServletRequest.class);
|
||||||
private final FakeResponse response = new FakeResponse();
|
private final 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 User user = new User("rdap.user@example.com", "gmail.com", "12345");
|
||||||
|
private final UserAuthInfo userAuthInfo = UserAuthInfo.create(user, false);
|
||||||
|
private final UserAuthInfo adminUserAuthInfo = UserAuthInfo.create(user, true);
|
||||||
private final RdapNameserverSearchAction action = new RdapNameserverSearchAction();
|
private final RdapNameserverSearchAction action = new RdapNameserverSearchAction();
|
||||||
|
|
||||||
private DomainResource domainCatLol;
|
private DomainResource domainCatLol;
|
||||||
|
@ -132,6 +144,7 @@ public class RdapNameserverSearchActionTest {
|
||||||
inject.setStaticField(Ofy.class, "clock", clock);
|
inject.setStaticField(Ofy.class, "clock", clock);
|
||||||
action.clock = clock;
|
action.clock = clock;
|
||||||
action.requestPath = RdapNameserverSearchAction.PATH;
|
action.requestPath = RdapNameserverSearchAction.PATH;
|
||||||
|
action.request = request;
|
||||||
action.response = response;
|
action.response = response;
|
||||||
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
action.rdapJsonFormatter = RdapTestHelper.getTestRdapJsonFormatter();
|
||||||
action.rdapResultSetMaxSize = 4;
|
action.rdapResultSetMaxSize = 4;
|
||||||
|
@ -139,6 +152,10 @@ public class RdapNameserverSearchActionTest {
|
||||||
action.rdapWhoisServer = null;
|
action.rdapWhoisServer = null;
|
||||||
action.ipParam = Optional.absent();
|
action.ipParam = Optional.absent();
|
||||||
action.nameParam = Optional.absent();
|
action.nameParam = Optional.absent();
|
||||||
|
action.registrarParam = Optional.absent();
|
||||||
|
action.includeDeletedParam = Optional.absent();
|
||||||
|
action.authResult = AuthResult.create(AuthLevel.USER, userAuthInfo);
|
||||||
|
action.sessionUtils = sessionUtils;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Object generateExpectedJson(String expectedOutputFile) {
|
private Object generateExpectedJson(String expectedOutputFile) {
|
||||||
|
@ -172,6 +189,7 @@ public class RdapNameserverSearchActionTest {
|
||||||
if (ipAddress != null) {
|
if (ipAddress != null) {
|
||||||
builder.put("ADDRESS", ipAddress);
|
builder.put("ADDRESS", ipAddress);
|
||||||
}
|
}
|
||||||
|
builder.put("STATUS", "active");
|
||||||
builder.put("TYPE", "nameserver");
|
builder.put("TYPE", "nameserver");
|
||||||
return JSONValue.parse(
|
return JSONValue.parse(
|
||||||
loadFileWithSubstitutions(this.getClass(), expectedOutputFile, builder.build()));
|
loadFileWithSubstitutions(this.getClass(), expectedOutputFile, builder.build()));
|
||||||
|
@ -210,6 +228,14 @@ public class RdapNameserverSearchActionTest {
|
||||||
.build());
|
.build());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void createDeletedHost() {
|
||||||
|
persistResource(
|
||||||
|
makeAndPersistHostResource("nsdeleted.cat.lol", "4.3.2.1", clock.nowUtc().minusYears(1))
|
||||||
|
.asBuilder()
|
||||||
|
.setDeletionTime(clock.nowUtc().minusMonths(1))
|
||||||
|
.build());
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testInvalidPath_rejected() throws Exception {
|
public void testInvalidPath_rejected() throws Exception {
|
||||||
action.requestPath = RdapDomainSearchAction.PATH + "/path";
|
action.requestPath = RdapDomainSearchAction.PATH + "/path";
|
||||||
|
@ -282,6 +308,20 @@ public class RdapNameserverSearchActionTest {
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatch_ns1_cat_lol_found_sameRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("TheRegistrar");
|
||||||
|
generateActualJsonWithName("ns1.cat.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatch_ns1_cat_lol_notFound_differentRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("unicoderegistrar");
|
||||||
|
generateActualJsonWithName("ns1.cat.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNameMatch_ns2_cat_lol_found() throws Exception {
|
public void testNameMatch_ns2_cat_lol_found() throws Exception {
|
||||||
assertThat(generateActualJsonWithName("ns2.cat.lol"))
|
assertThat(generateActualJsonWithName("ns2.cat.lol"))
|
||||||
|
@ -347,6 +387,20 @@ public class RdapNameserverSearchActionTest {
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatch_nsstar_cat_lol_found_sameRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("TheRegistrar");
|
||||||
|
generateActualJsonWithName("ns*.cat.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatch_nsstar_cat_lol_notFound_differentRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("unicoderegistrar");
|
||||||
|
generateActualJsonWithName("ns*.cat.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNameMatch_nstar_cat_lol_found() throws Exception {
|
public void testNameMatch_nstar_cat_lol_found() throws Exception {
|
||||||
generateActualJsonWithName("n*.cat.lol");
|
generateActualJsonWithName("n*.cat.lol");
|
||||||
|
@ -359,6 +413,20 @@ public class RdapNameserverSearchActionTest {
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatch_star_cat_lol_found_sameRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("TheRegistrar");
|
||||||
|
generateActualJsonWithName("*.cat.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatch_star_cat_lol_notFound_differentRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("unicoderegistrar");
|
||||||
|
generateActualJsonWithName("*.cat.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNameMatch_nsstar_found() throws Exception {
|
public void testNameMatch_nsstar_found() throws Exception {
|
||||||
generateActualJsonWithName("ns*");
|
generateActualJsonWithName("ns*");
|
||||||
|
@ -423,28 +491,6 @@ public class RdapNameserverSearchActionTest {
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAddressMatchV4Address_found() throws Exception {
|
|
||||||
assertThat(generateActualJsonWithIp("1.2.3.4"))
|
|
||||||
.isEqualTo(
|
|
||||||
generateExpectedJsonForNameserver(
|
|
||||||
"ns1.cat.lol", null, "2-ROID", "v4", "1.2.3.4", "rdap_host_linked.json"));
|
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAddressMatchV6Address_foundMultiple() throws Exception {
|
|
||||||
assertThat(generateActualJsonWithIp("bad:f00d:cafe::15:beef"))
|
|
||||||
.isEqualTo(generateExpectedJson("rdap_multiple_hosts.json"));
|
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void testAddressMatchLocalhost_notFound() throws Exception {
|
|
||||||
generateActualJsonWithIp("127.0.0.1");
|
|
||||||
assertThat(response.getStatus()).isEqualTo(404);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testNameMatchDeletedHost_notFound() throws Exception {
|
public void testNameMatchDeletedHost_notFound() throws Exception {
|
||||||
persistResource(hostNs1CatLol.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
persistResource(hostNs1CatLol.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||||
|
@ -461,6 +507,112 @@ public class RdapNameserverSearchActionTest {
|
||||||
assertThat(response.getStatus()).isEqualTo(404);
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatchDeleted_notFound_includeDeletedNotSpecified() throws Exception {
|
||||||
|
createDeletedHost();
|
||||||
|
generateActualJsonWithName("nsdeleted.cat.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatchDeleted_notFound_notLoggedIn() throws Exception {
|
||||||
|
createDeletedHost();
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(false);
|
||||||
|
generateActualJsonWithName("nsdeleted.cat.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatchDeleted_notFound_loggedInAsDifferentRegistrar() throws Exception {
|
||||||
|
createDeletedHost();
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("unicoderegistrar");
|
||||||
|
generateActualJsonWithName("nsdeleted.cat.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatchDeleted_found_loggedInAsCorrectRegistrar() throws Exception {
|
||||||
|
createDeletedHost();
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("TheRegistrar");
|
||||||
|
generateActualJsonWithName("nsdeleted.cat.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatchDeleted_found_loggedInAsAdmin() throws Exception {
|
||||||
|
createDeletedHost();
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
action.authResult = AuthResult.create(AuthLevel.USER, adminUserAuthInfo);
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, adminUserAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("irrelevant");
|
||||||
|
generateActualJsonWithName("nsdeleted.cat.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatchDeleted_found_loggedInAndRequestingSameRegistrar() throws Exception {
|
||||||
|
createDeletedHost();
|
||||||
|
action.registrarParam = Optional.of("TheRegistrar");
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("TheRegistrar");
|
||||||
|
generateActualJsonWithName("nsdeleted.cat.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testNameMatchDeleted_notFound_loggedInButRequestingDifferentRegistrar()
|
||||||
|
throws Exception {
|
||||||
|
createDeletedHost();
|
||||||
|
action.registrarParam = Optional.of("unicoderegistrar");
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("TheRegistrar");
|
||||||
|
generateActualJsonWithName("nsdeleted.cat.lol");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchV4Address_found() throws Exception {
|
||||||
|
assertThat(generateActualJsonWithIp("1.2.3.4"))
|
||||||
|
.isEqualTo(
|
||||||
|
generateExpectedJsonForNameserver(
|
||||||
|
"ns1.cat.lol", null, "2-ROID", "v4", "1.2.3.4", "rdap_host_linked.json"));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchV4Address_found_sameRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("TheRegistrar");
|
||||||
|
generateActualJsonWithIp("1.2.3.4");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchV4Address_notFound_differentRegistrarRequested() throws Exception {
|
||||||
|
action.registrarParam = Optional.of("unicoderegistrar");
|
||||||
|
generateActualJsonWithIp("1.2.3.4");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchV6Address_foundMultiple() throws Exception {
|
||||||
|
assertThat(generateActualJsonWithIp("bad:f00d:cafe::15:beef"))
|
||||||
|
.isEqualTo(generateExpectedJson("rdap_multiple_hosts.json"));
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchLocalhost_notFound() throws Exception {
|
||||||
|
generateActualJsonWithIp("127.0.0.1");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
public void testAddressMatchDeletedHost_notFound() throws Exception {
|
public void testAddressMatchDeletedHost_notFound() throws Exception {
|
||||||
persistResource(hostNs1CatLol.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
persistResource(hostNs1CatLol.asBuilder().setDeletionTime(clock.nowUtc().minusDays(1)).build());
|
||||||
|
@ -492,4 +644,74 @@ public class RdapNameserverSearchActionTest {
|
||||||
.isEqualTo(generateExpectedJson("rdap_truncated_hosts.json"));
|
.isEqualTo(generateExpectedJson("rdap_truncated_hosts.json"));
|
||||||
assertThat(response.getStatus()).isEqualTo(200);
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchDeleted_notFound_includeDeletedNotSpecified() throws Exception {
|
||||||
|
createDeletedHost();
|
||||||
|
generateActualJsonWithIp("4.3.2.1");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchDeleted_notFound_notLoggedIn() throws Exception {
|
||||||
|
createDeletedHost();
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(false);
|
||||||
|
generateActualJsonWithIp("4.3.2.1");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchDeleted_notFound_loggedInAsDifferentRegistrar() throws Exception {
|
||||||
|
createDeletedHost();
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("unicoderegistrar");
|
||||||
|
generateActualJsonWithIp("4.3.2.1");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchDeleted_found_loggedInAsCorrectRegistrar() throws Exception {
|
||||||
|
createDeletedHost();
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("TheRegistrar");
|
||||||
|
generateActualJsonWithIp("4.3.2.1");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchDeleted_found_loggedInAsAdmin() throws Exception {
|
||||||
|
createDeletedHost();
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
action.authResult = AuthResult.create(AuthLevel.USER, adminUserAuthInfo);
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, adminUserAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("irrelevant");
|
||||||
|
generateActualJsonWithIp("4.3.2.1");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchDeleted_found_loggedInAndRequestingSameRegisrar() throws Exception {
|
||||||
|
createDeletedHost();
|
||||||
|
action.registrarParam = Optional.of("TheRegistrar");
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("TheRegistrar");
|
||||||
|
generateActualJsonWithIp("4.3.2.1");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(200);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testAddressMatchDeleted_notFound_loggedButRequestingDiffentRegistrar()
|
||||||
|
throws Exception {
|
||||||
|
createDeletedHost();
|
||||||
|
action.registrarParam = Optional.of("unicoderegistrar");
|
||||||
|
action.includeDeletedParam = Optional.of(true);
|
||||||
|
when(sessionUtils.checkRegistrarConsoleLogin(request, userAuthInfo)).thenReturn(true);
|
||||||
|
when(sessionUtils.getRegistrarClientId(request)).thenReturn("TheRegistrar");
|
||||||
|
generateActualJsonWithIp("4.3.2.1");
|
||||||
|
assertThat(response.getStatus()).isEqualTo(404);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"status": [
|
"status": [
|
||||||
"active"
|
"%STATUS%"
|
||||||
],
|
],
|
||||||
"ldhName": "%NAME%",
|
"ldhName": "%NAME%",
|
||||||
"handle": "%HANDLE%",
|
"handle": "%HANDLE%",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue