Conform to RDAP Response Profile 15feb19

This is only about the Response Profile, not the Technical Implementation guide.

The Response Profile can be found at https://www.icann.org/en/system/files/files/rdap-response-profile-15feb19-en.pdf

-------------
Created by MOE: https://github.com/google/moe
MOE_MIGRATED_REVID=250277559
This commit is contained in:
guyben 2019-05-28 07:36:33 -07:00 committed by jianglai
parent b34a828b71
commit c79e0ea670
89 changed files with 4102 additions and 5815 deletions

View file

@ -32,6 +32,8 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
@XmlType(name = "dsData")
public class DelegationSignerData extends ImmutableObject {
private DelegationSignerData() {}
/** The identifier for this particular key in the domain. */
int keyTag;
@ -74,6 +76,10 @@ public class DelegationSignerData extends ImmutableObject {
return digest;
}
public String getDigestAsString() {
return digest == null ? "" : DatatypeConverter.printHexBinary(digest);
}
public static DelegationSignerData create(
int keyTag, int algorithm, int digestType, byte[] digest) {
DelegationSignerData instance = new DelegationSignerData();
@ -84,6 +90,11 @@ public class DelegationSignerData extends ImmutableObject {
return instance;
}
public static DelegationSignerData create(
int keyTag, int algorithm, int digestType, String digestAsHex) {
return create(keyTag, algorithm, digestType, DatatypeConverter.parseHexBinary(digestAsHex));
}
/**
* Returns the presentation format of this DS record.
*

View file

@ -14,6 +14,7 @@ java_library(
"//java/google/registry/request",
"//java/google/registry/request/auth",
"//java/google/registry/util",
"//third_party/jaxb",
"//third_party/objectify:objectify-v4_1",
"@com_google_auto_value",
"@com_google_code_findbugs_jsr305",

View file

@ -162,8 +162,10 @@ public abstract class RdapActionBase implements Runnable {
setPayload(replyObject);
metricInformationBuilder.setStatusCode(SC_OK);
} catch (HttpException e) {
logger.atInfo().withCause(e).log("Error in RDAP");
setError(e.getResponseCode(), e.getResponseCodeString(), e.getMessage());
} catch (URISyntaxException | IllegalArgumentException e) {
logger.atInfo().withCause(e).log("Bad request in RDAP");
setError(SC_BAD_REQUEST, "Bad Request", "Not a valid " + getHumanReadableObjectTypeName());
} catch (RuntimeException e) {
setError(SC_INTERNAL_SERVER_ERROR, "Internal Server Error", "An error was encountered");
@ -240,18 +242,17 @@ public abstract class RdapActionBase implements Runnable {
*/
boolean isAuthorized(EppResource eppResource) {
return getRequestTime().isBefore(eppResource.getDeletionTime())
|| (shouldIncludeDeleted()
&& rdapAuthorization
.isAuthorizedForClientId(eppResource.getPersistedCurrentSponsorClientId()));
|| (shouldIncludeDeleted()
&& rdapAuthorization.isAuthorizedForClientId(
eppResource.getPersistedCurrentSponsorClientId()));
}
/**
* Returns true if the EPP resource should be visible.
*
* <p>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.
* <p>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) {
return isAuthorized(eppResource)
@ -262,10 +263,9 @@ public abstract class RdapActionBase implements Runnable {
/**
* Returns true if the EPP resource should be visible.
*
* <p>This is true iff:
* 1. The passed in resource exists and is not deleted (deleted ones will have been projected
* forward in time to empty),
* 2. The request did not specify a registrar to filter on, or the registrar matches.
* <p>This is true iff: 1. The passed in resource exists and is not deleted (deleted ones will
* have been projected forward in time to empty), 2. The request did not specify a registrar to
* filter on, or the registrar matches.
*/
boolean shouldBeVisible(Optional<? extends EppResource> eppResource) {
return eppResource.isPresent() && shouldBeVisible(eppResource.get());
@ -463,19 +463,19 @@ public abstract class RdapActionBase implements Runnable {
* 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
* added if appropriate
* @param checkForVisibility true if the results should be checked to make sure they are visible;
* normally this should be equal to the shouldIncludeDeleted setting, but in cases where
* the query could not check deletion status (due to Datastore limitations such as the
* limit of one field queried for inequality, for instance), it may need to be set to true
* even when not including deleted records
* normally this should be equal to the shouldIncludeDeleted setting, but in cases where the
* query could not check deletion status (due to Datastore limitations such as the limit of
* one field queried for inequality, for instance), it may need to be set to true even when
* not including deleted records
* @param querySizeLimit the maximum number of items the query is expected to return, usually
* because the limit has been set
* @return an {@link RdapResultSet} 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, and the number of items returned by the
* query is greater than or equal to the maximum number we might have expected
* because the limit has been set
* @return an {@link RdapResultSet} 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,
* and the number of items returned by the query is greater than or equal to the maximum
* number we might have expected
*/
<T extends EppResource> RdapResultSet<T> getMatchingResources(
Query<T> query, boolean checkForVisibility, int querySizeLimit) {

View file

@ -43,9 +43,7 @@ final class RdapDataStructures {
public JsonArray toJson() {
JsonArray jsonArray = new JsonArray();
// Conformance to RFC7483
// TODO(b/127490882) check if we need to Add back the rdap_level_0 string, as I think that
// just means we conform to the RFC, which we do
// jsonArray.add("rdap_level_0");
jsonArray.add("rdap_level_0");
// Conformance to the RDAP Response Profile V2.1
// (see section 1.3)

View file

@ -65,8 +65,6 @@ public class RdapDomainAction extends RdapActionBase {
if (!shouldBeVisible(domainBase)) {
throw new NotFoundException(pathSearchString + " not found");
}
return rdapJsonFormatter.makeRdapJsonForDomain(
domainBase.get(),
OutputDataType.FULL);
return rdapJsonFormatter.createRdapDomain(domainBase.get(), OutputDataType.FULL);
}
}

View file

@ -122,8 +122,9 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
if (!LDH_PATTERN.matcher(nsLdhNameParam.get()).matches()) {
throw new BadRequestException("Invalid value of nsLdhName parameter");
}
results = searchByNameserverLdhName(
recordWildcardType(RdapSearchPattern.create(nsLdhNameParam.get(), true)));
results =
searchByNameserverLdhName(
recordWildcardType(RdapSearchPattern.create(nsLdhNameParam.get(), true)));
} else {
metricInformationBuilder.setSearchType(SearchType.BY_NAMESERVER_ADDRESS);
metricInformationBuilder.setWildcardType(WildcardType.NO_WILDCARD);
@ -182,9 +183,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
return searchByDomainNameByTld(partialStringQuery.getSuffix());
}
/**
* Searches for domains by domain name without a wildcard or interest in deleted entries.
*/
/** Searches for domains by domain name without a wildcard or interest in deleted entries. */
private DomainSearchResponse searchByDomainNameWithoutWildcard(
final RdapSearchPattern partialStringQuery) {
Optional<DomainBase> domainBase =
@ -388,15 +387,14 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
* <p>In theory, we could have any number of hosts using the same IP address. To make sure we get
* all the associated domains, we have to retrieve all of them, and use them to look up domains.
* This could open us up to a kind of DoS attack if huge number of hosts are defined on a single
* IP. To avoid this, fetch only the first {@link #maxNameserversInFirstStage} nameservers. In
* all normal circumstances, this should be orders of magnitude more than there actually are. But
* it could result in us missing some domains.
* IP. To avoid this, fetch only the first {@link #maxNameserversInFirstStage} nameservers. In all
* normal circumstances, this should be orders of magnitude more than there actually are. But it
* could result in us missing some domains.
*
* <p>The includeDeleted parameter does NOT cause deleted nameservers to be searched, only deleted
* domains which used to be connected to an undeleted nameserver.
*/
private DomainSearchResponse searchByNameserverIp(
final InetAddress inetAddress) {
private DomainSearchResponse searchByNameserverIp(final InetAddress inetAddress) {
Query<HostResource> query =
queryItems(
HostResource.class,
@ -419,8 +417,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
* <p>This method is called by {@link #searchByNameserverLdhName} and {@link
* #searchByNameserverIp} after they assemble the relevant host keys.
*/
private DomainSearchResponse searchByNameserverRefs(
final Iterable<Key<HostResource>> hostKeys) {
private DomainSearchResponse searchByNameserverRefs(final Iterable<Key<HostResource>> hostKeys) {
// We must break the query up into chunks, because the in operator is limited to 30 subqueries.
// Since it is possible for the same domain to show up more than once in our result list (if
// we do a wildcard nameserver search that returns multiple nameservers used by the same
@ -459,8 +456,8 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
return makeSearchResults(
domains,
(numHostKeysSearched >= maxNameserversInFirstStage)
? IncompletenessWarningType.MIGHT_BE_INCOMPLETE
: IncompletenessWarningType.COMPLETE,
? IncompletenessWarningType.MIGHT_BE_INCOMPLETE
: IncompletenessWarningType.COMPLETE,
(numHostKeysSearched > 0) ? Optional.of((long) domains.size()) : Optional.empty());
}
@ -471,8 +468,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
}
/** Output JSON from data in an {@link RdapResultSet} object. */
private DomainSearchResponse makeSearchResults(
RdapResultSet<DomainBase> resultSet) {
private DomainSearchResponse makeSearchResults(RdapResultSet<DomainBase> resultSet) {
return makeSearchResults(
resultSet.resources(),
resultSet.incompletenessWarningType(),
@ -501,7 +497,7 @@ public class RdapDomainSearchAction extends RdapSearchActionBase {
newCursor = Optional.of(domain.getFullyQualifiedDomainName());
builder
.domainSearchResultsBuilder()
.add(rdapJsonFormatter.makeRdapJsonForDomain(domain, outputDataType));
.add(rdapJsonFormatter.createRdapDomain(domain, outputDataType));
}
if (rdapResultSetMaxSize < domains.size()) {
builder.setNextPageUri(createNavigationUri(newCursor.get()));

View file

@ -19,6 +19,7 @@ import static google.registry.rdap.RdapUtils.getRegistrarByIanaIdentifier;
import static google.registry.request.Action.Method.GET;
import static google.registry.request.Action.Method.HEAD;
import com.google.common.collect.ImmutableSet;
import com.google.common.primitives.Longs;
import com.google.re2j.Pattern;
import com.googlecode.objectify.Key;
@ -72,10 +73,8 @@ public class RdapEntityAction extends RdapActionBase {
// As per Andy Newton on the regext mailing list, contacts by themselves have no role, since
// they are global, and might have different roles for different domains.
if ((contactResource != null) && shouldBeVisible(contactResource)) {
return rdapJsonFormatter.makeRdapJsonForContact(
contactResource,
Optional.empty(),
OutputDataType.FULL);
return rdapJsonFormatter.createRdapContactEntity(
contactResource, ImmutableSet.of(), OutputDataType.FULL);
}
}
Long ianaIdentifier = Longs.tryParse(pathSearchString);
@ -83,8 +82,7 @@ public class RdapEntityAction extends RdapActionBase {
wasValidKey = true;
Optional<Registrar> registrar = getRegistrarByIanaIdentifier(ianaIdentifier);
if (registrar.isPresent() && shouldBeVisible(registrar.get())) {
return rdapJsonFormatter.makeRdapJsonForRegistrar(
registrar.get(), OutputDataType.FULL);
return rdapJsonFormatter.createRdapRegistrarEntity(registrar.get(), OutputDataType.FULL);
}
}
// At this point, we have failed to find either a contact or a registrar.

View file

@ -21,6 +21,7 @@ import static google.registry.request.Action.Method.GET;
import static google.registry.request.Action.Method.HEAD;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Streams;
import com.google.common.primitives.Booleans;
@ -380,10 +381,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
shouldIncludeDeleted(),
querySizeLimit);
}
return makeSearchResults(
contactResultSet,
registrars,
QueryType.HANDLE);
return makeSearchResults(contactResultSet, registrars, QueryType.HANDLE);
}
}
@ -406,9 +404,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
* properties of the {@link RdapResultSet} structure and passes them as separate arguments.
*/
private EntitySearchResponse makeSearchResults(
RdapResultSet<ContactResource> resultSet,
List<Registrar> registrars,
QueryType queryType) {
RdapResultSet<ContactResource> resultSet, List<Registrar> registrars, QueryType queryType) {
return makeSearchResults(
resultSet.resources(),
resultSet.incompletenessWarningType(),
@ -424,10 +420,10 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
*
* @param contacts the list of contacts which can be returned
* @param incompletenessWarningType MIGHT_BE_INCOMPLETE if the list of contacts might be
* incomplete; this only matters if the total count of contacts and registrars combined is
* less than a full result set's worth
* incomplete; this only matters if the total count of contacts and registrars combined is
* less than a full result set's worth
* @param numContactsRetrieved the number of contacts retrieved in the process of generating the
* results
* results
* @param registrars the list of registrars which can be returned
* @param queryType whether the query was by full name or by handle
* @return an {@link RdapSearchResults} object
@ -460,10 +456,11 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
for (ContactResource contact : Iterables.limit(contacts, rdapResultSetMaxSize)) {
// As per Andy Newton on the regext mailing list, contacts by themselves have no role, since
// they are global, and might have different roles for different domains.
builder.entitySearchResultsBuilder().add(rdapJsonFormatter.makeRdapJsonForContact(
contact,
Optional.empty(),
outputDataType));
builder
.entitySearchResultsBuilder()
.add(
rdapJsonFormatter.createRdapContactEntity(
contact, ImmutableSet.of(), outputDataType));
newCursor =
Optional.of(
CONTACT_CURSOR_PREFIX
@ -476,9 +473,7 @@ public class RdapEntitySearchAction extends RdapSearchActionBase {
Iterables.limit(registrars, rdapResultSetMaxSize - contacts.size())) {
builder
.entitySearchResultsBuilder()
.add(
rdapJsonFormatter.makeRdapJsonForRegistrar(
registrar, outputDataType));
.add(rdapJsonFormatter.createRdapRegistrarEntity(registrar, outputDataType));
newCursor = Optional.of(REGISTRAR_CURSOR_PREFIX + registrar.getRegistrarName());
}
}

View file

@ -51,11 +51,12 @@ public class RdapIcannStandardInformation {
.build())
.build();
/** Required by ICANN RDAP Profile section 1.5.20. */
/** Required by ICANN RDAP Response Profile section 2.11. */
private static final Notice INACCURACY_COMPLAINT_FORM_NOTICE =
Notice.builder()
.setTitle("RDDS Inaccuracy Complaint Form")
.setDescription(
"URL of the ICANN Whois Inaccuracy Complaint Form: https://www.icann.org/wicf")
"URL of the ICANN RDDS Inaccuracy Complaint Form: https://www.icann.org/wicf")
.addLink(
Link.builder()
.setValue("https://www.icann.org/wicf")
@ -71,6 +72,7 @@ public class RdapIcannStandardInformation {
CONFORMANCE_NOTICE,
// RDAP Response Profile 2.6.3
DOMAIN_STATUS_CODES_NOTICE,
// RDAP Response Profile 2.11
INACCURACY_COMPLAINT_FORM_NOTICE);
/** Boilerplate remarks required by nameserver and entity responses. */
@ -125,21 +127,14 @@ public class RdapIcannStandardInformation {
static final ImmutableList<Notice> POSSIBLY_INCOMPLETE_NOTICES =
ImmutableList.of(POSSIBLY_INCOMPLETE_RESULT_SET_NOTICE);
/** Included when the requester is not logged in as the owner of the domain being returned. */
static final Remark DOMAIN_CONTACTS_HIDDEN_DATA_REMARK =
Remark.builder()
.setTitle("Contacts Hidden")
.setDescription("Domain contacts are visible only to the owning registrar.")
.setType(Remark.Type.OBJECT_TRUNCATED_UNEXPLAINABLE)
.build();
/**
* Included when requester is not logged in as the owner of the contact being returned. Format
* required by ICANN RDAP Response Profile 15feb19 section 2.7.4.3.
* Included when requester is not logged in as the owner of the contact being returned.
*
* <p>Format required by ICANN RDAP Response Profile 15feb19 section 2.7.4.3.
*/
static final Remark CONTACT_PERSONAL_DATA_HIDDEN_DATA_REMARK =
Remark.builder()
.setTitle("Redacted for Privacy")
.setTitle("REDACTED FOR PRIVACY")
.setDescription(
"Some of the data in this object has been removed.",
"Contact personal data is visible only to the owning registrar.")
@ -154,4 +149,30 @@ public class RdapIcannStandardInformation {
.setType("text/html")
.build())
.build();
/**
* String that replaces GDPR redacted values.
*
* <p>GTLD Registration Data Temp Spec 17may18, Appendix A, 2.2: Fields required to be "redacted"
* MUST privide in the value section text similar to "REDACTED FOR PRIVACY"
*/
static final String CONTACT_REDACTED_VALUE = "REDACTED FOR PRIVACY";
/**
* Included in ALL contact responses, even if the user is authorized.
*
* <p>Format required by ICANN RDAP Response Profile 15feb19 section 2.7.5.3.
*
* <p>NOTE that unlike other redacted fields, there's no allowance to give the email to authorized
* users or allow for registrar consent.
*/
static final Remark CONTACT_EMAIL_REDACTED_FOR_DOMAIN =
Remark.builder()
.setTitle("EMAIL REDACTED FOR PRIVACY")
.setDescription(
"Please query the RDDS service of the Registrar of Record identifies in this output"
+ " for information on how to contact the Registrant of the queried domain"
+ " name.")
.setType(Remark.Type.OBJECT_REDACTED_AUTHORIZATION)
.build();
}

File diff suppressed because it is too large Load diff

View file

@ -67,6 +67,6 @@ public class RdapNameserverAction extends RdapActionBase {
if (!shouldBeVisible(hostResource)) {
throw new NotFoundException(pathSearchString + " not found");
}
return rdapJsonFormatter.makeRdapJsonForHost(hostResource.get(), OutputDataType.FULL);
return rdapJsonFormatter.createRdapNameserver(hostResource.get(), OutputDataType.FULL);
}
}

View file

@ -167,10 +167,9 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
NameserverSearchResponse.Builder builder =
NameserverSearchResponse.builder()
.setIncompletenessWarningType(IncompletenessWarningType.COMPLETE);
builder.nameserverSearchResultsBuilder().add(
rdapJsonFormatter.makeRdapJsonForHost(
hostResource.get(),
OutputDataType.FULL));
builder
.nameserverSearchResultsBuilder()
.add(rdapJsonFormatter.createRdapNameserver(hostResource.get(), OutputDataType.FULL));
return builder.build();
}
@ -230,8 +229,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
getDeletedItemHandling(),
querySizeLimit);
return makeSearchResults(
getMatchingResources(query, shouldIncludeDeleted(), querySizeLimit),
CursorType.NAME);
getMatchingResources(query, shouldIncludeDeleted(), querySizeLimit), CursorType.NAME);
}
/** Searches for nameservers by IP address, returning a JSON array of nameserver info maps. */
@ -248,8 +246,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
getDeletedItemHandling(),
querySizeLimit);
return makeSearchResults(
getMatchingResources(query, shouldIncludeDeleted(), querySizeLimit),
CursorType.ADDRESS);
getMatchingResources(query, shouldIncludeDeleted(), querySizeLimit), CursorType.ADDRESS);
}
/** Output JSON for a lists of hosts contained in an {@link RdapResultSet}. */
@ -282,7 +279,7 @@ public class RdapNameserverSearchAction extends RdapSearchActionBase {
: host.getRepoId());
builder
.nameserverSearchResultsBuilder()
.add(rdapJsonFormatter.makeRdapJsonForHost(host, outputDataType));
.add(rdapJsonFormatter.createRdapNameserver(host, outputDataType));
}
if (rdapResultSetMaxSize < hosts.size()) {
builder.setNextPageUri(createNavigationUri(newCursor.get()));

View file

@ -25,6 +25,7 @@ import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonPrimitive;
import google.registry.model.domain.secdns.DelegationSignerData;
import google.registry.rdap.AbstractJsonableObject.RestrictJsonNames;
import google.registry.rdap.RdapDataStructures.Event;
import google.registry.rdap.RdapDataStructures.EventWithoutActor;
@ -149,7 +150,6 @@ final class RdapObjectClasses {
*
* All Actions need to return an object of this type.
*/
@RestrictJsonNames("*")
abstract static class ReplyPayloadBase extends AbstractJsonableObject {
final BoilerplateType boilerplateType;
@ -207,6 +207,18 @@ final class RdapObjectClasses {
@JsonableElement abstract ImmutableList<Link> links();
@JsonableElement abstract ImmutableList<Event> events();
/**
* Required event for all response objects, but not for internal objects.
*
* <p>Meaning it's required in, e.g., an RdapNameserver object that is a response to a
* Nameserver query, but not to an RdapNameserver that's part of an RdapDomain response to a
* Domain query.
*
* <p>RDAP Response Profile 2.3.1.3, 3.3, 4.4
*/
@JsonableElement("events[]")
abstract Optional<Event> lastUpdateOfRdapDatabaseEvent();
/**
* WHOIS server displayed in RDAP query responses.
*
@ -232,16 +244,20 @@ final class RdapObjectClasses {
abstract ImmutableList.Builder<Link> linksBuilder();
abstract B setPort43(Port43WhoisServer port43);
abstract ImmutableList.Builder<Event> eventsBuilder();
abstract B setLastUpdateOfRdapDatabaseEvent(Event event);
}
}
/**
* The Entity Object Class defined in 5.1 of RFC7483.
*
* <p>Entities are used both for Contacts and for Registrars. We will create different subobjects
* for each one for type safety.
*
* <p>We're missing the "autnums" and "networks" fields
*/
@RestrictJsonNames({"entities[]", "entitySearchResults[]"})
@AutoValue
abstract static class RdapEntity extends RdapObjectBase {
/** Role values specified in RFC 7483 § 10.2.4. */
@ -280,17 +296,50 @@ final class RdapObjectClasses {
@JsonableElement abstract ImmutableSet<Role> roles();
@JsonableElement abstract ImmutableList<EventWithoutActor> asEventActor();
private abstract static class Builder<B extends Builder<B>> extends RdapObjectBase.Builder<B> {
abstract B setVcardArray(VcardArray vcardArray);
abstract ImmutableSet.Builder<Role> rolesBuilder();
abstract ImmutableList.Builder<EventWithoutActor> asEventActorBuilder();
}
}
/**
* Registrar version of the Entity Object Class defined in 5.1 of RFC7483.
*
* <p>Entities are used both for Contacts and for Registrars. We will create different subobjects
* for each one for type safety.
*/
@AutoValue
abstract static class RdapRegistrarEntity extends RdapEntity {
static Builder builder() {
return new AutoValue_RdapObjectClasses_RdapEntity.Builder();
return new AutoValue_RdapObjectClasses_RdapRegistrarEntity.Builder();
}
@AutoValue.Builder
abstract static class Builder extends RdapObjectBase.Builder<Builder> {
abstract Builder setVcardArray(VcardArray vcardArray);
abstract ImmutableSet.Builder<Role> rolesBuilder();
abstract ImmutableList.Builder<EventWithoutActor> asEventActorBuilder();
abstract static class Builder extends RdapEntity.Builder<Builder> {
abstract RdapRegistrarEntity build();
}
}
abstract RdapEntity build();
/**
* Contact version of the Entity Object Class defined in 5.1 of RFC7483.
*
* <p>Entities are used both for Contacts and for Registrars. We will create different subobjects
* for each one for type safety.
*/
@AutoValue
abstract static class RdapContactEntity extends RdapEntity {
static Builder builder() {
return new AutoValue_RdapObjectClasses_RdapContactEntity.Builder();
}
@AutoValue.Builder
abstract static class Builder extends RdapEntity.Builder<Builder> {
abstract RdapContactEntity build();
}
}
@ -301,6 +350,10 @@ final class RdapObjectClasses {
*
* <p>See RDAP Response Profile 15feb19 sections 2.1 and 4.1.
*
* <p>Note the ldhName field is only required for non-IDN names or IDN names when the query was an
* A-label. It is optional for IDN names when the query was a U-label. Because we don't want to
* remember the query when building the results, we always show it.
*
* <p>Not part of the spec, but seems convenient.
*/
private abstract static class RdapNamedObjectBase extends RdapObjectBase {
@ -374,7 +427,80 @@ final class RdapObjectClasses {
abstract RdapNameserver build();
}
}
/** Object defined in RFC7483 section 5.3, only used for RdapDomain. */
@RestrictJsonNames("secureDNS")
@AutoValue
abstract static class SecureDns extends AbstractJsonableObject {
@RestrictJsonNames("dsData[]")
@AutoValue
abstract static class DsData extends AbstractJsonableObject {
@JsonableElement
abstract int keyTag();
@JsonableElement
abstract int algorithm();
@JsonableElement
abstract String digest();
@JsonableElement
abstract int digestType();
static DsData create(DelegationSignerData dsData) {
return new AutoValue_RdapObjectClasses_SecureDns_DsData(
dsData.getKeyTag(),
dsData.getAlgorithm(),
dsData.getDigestAsString(),
dsData.getDigestType());
}
}
/** true if the zone has been signed, false otherwise. */
@JsonableElement
abstract boolean zoneSigned();
/** true if there are DS records in the parent, false otherwise. */
@JsonableElement
boolean delegationSigned() {
return !dsData().isEmpty();
}
/**
* an integer representing the signature lifetime in seconds to be used when creating the RRSIG
* DS record in the parent zone [RFC5910].
*
* <p>Note that although it isn't given as optional in RFC7483, in RFC5910 it's mentioned as
* optional. Also, our code doesn't support it at all - so it's set to always be empty.
*/
@JsonableElement
Optional<Integer> maxSigLife() {
return Optional.empty();
}
@JsonableElement
abstract ImmutableList<DsData> dsData();
static Builder builder() {
return new AutoValue_RdapObjectClasses_SecureDns.Builder();
}
abstract Builder toBuilder();
@AutoValue.Builder
abstract static class Builder {
abstract Builder setZoneSigned(boolean zoneSigned);
abstract ImmutableList.Builder<DsData> dsDataBuilder();
Builder addDsData(DelegationSignerData dsData) {
dsDataBuilder().add(DsData.create(dsData));
return this;
}
abstract SecureDns build();
}
}
/**
@ -388,6 +514,9 @@ final class RdapObjectClasses {
@JsonableElement abstract ImmutableList<RdapNameserver> nameservers();
@JsonableElement("secureDNS")
abstract Optional<SecureDns> secureDns();
RdapDomain() {
super(BoilerplateType.DOMAIN, ObjectClassName.DOMAIN);
}
@ -400,6 +529,8 @@ final class RdapObjectClasses {
abstract static class Builder extends RdapNamedObjectBase.Builder<Builder> {
abstract ImmutableList.Builder<RdapNameserver> nameserversBuilder();
abstract Builder setSecureDns(SecureDns secureDns);
abstract RdapDomain build();
}
}

View file

@ -49,8 +49,7 @@ public final class RequestModule {
private final AuthResult authResult;
@VisibleForTesting
public RequestModule(
HttpServletRequest req, HttpServletResponse rsp) {
public RequestModule(HttpServletRequest req, HttpServletResponse rsp) {
this(req, rsp, AuthResult.NOT_AUTHENTICATED);
}