From 85f55358114e3ffe630d9f7dab6877a9f176cdad Mon Sep 17 00:00:00 2001 From: mountford Date: Thu, 8 Feb 2018 13:06:14 -0800 Subject: [PATCH] RDAP: Change data policy remark for redacted contacts Changes the code to be in compliance with the RDAP Pilot Profile document, which specifies: 1.4.11. If permitted or required by an ICANN agreement provision, waiver, or Consensus Policy, an RDAP response may contain redacted registrant, administrative, technical and/or other contact information. If any information is redacted, the response MUST include a remarks member with title "Data Policy", type "object truncated due to authorization", a description containing the string "Some of the data in this object has been removed" and a links member with the elements rel:alternate and href indicating where the data policy can be found. An entity with redacted information MUST include the "removed" value in the status element. We were using the "removed" status to indicate deleted contacts and inactive registrars. Instead, we will now use "inactive", so that we can use "removed" to indicated redaction. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=185039201 --- .../rdap/RdapIcannStandardInformation.java | 22 ++++++++++--- .../registry/rdap/RdapJsonFormatter.java | 32 +++++++++++++------ .../registry/rdap/RdapEntityActionTest.java | 8 ++--- .../rdap/RdapEntitySearchActionTest.java | 16 +++++----- .../rdap/RdapNameserverActionTest.java | 6 ++-- .../google/registry/rdap/RdapTestHelper.java | 20 +++++++++--- ...p_associated_contact_no_personal_data.json | 2 +- .../rdap/testdata/rdap_contact_deleted.json | 2 +- ..._contact_no_personal_data_with_remark.json | 16 ++++++++-- .../rdap/testdata/rdap_domain_deleted.json | 2 +- .../rdapjson_registrant_logged_out.json | 16 ++++++++-- ...dapjson_registrant_summary_logged_out.json | 14 ++++++-- 12 files changed, 112 insertions(+), 44 deletions(-) diff --git a/java/google/registry/rdap/RdapIcannStandardInformation.java b/java/google/registry/rdap/RdapIcannStandardInformation.java index 976487b60..ba246193f 100644 --- a/java/google/registry/rdap/RdapIcannStandardInformation.java +++ b/java/google/registry/rdap/RdapIcannStandardInformation.java @@ -133,13 +133,27 @@ public class RdapIcannStandardInformation { "type", "object truncated due to unexplainable reasons"); - /** Included when requester is not logged in as the owner of the contact being returned. */ + /** + * Included when requester is not logged in as the owner of the contact being returned. Format + * required by ICANN RDAP Pilot Profile draft section 1.4.11. + */ static final ImmutableMap CONTACT_PERSONAL_DATA_HIDDEN_DATA_REMARK = ImmutableMap.of( "title", - "Contact Personal Data Hidden", + "Data Policy", "description", - ImmutableList.of("Contact personal data is visible only to the owning registrar."), + ImmutableList.of( + "Some of the data in this object has been removed.", + "Contact personal data is visible only to the owning registrar."), "type", - "object truncated due to unexplainable reasons"); + "object truncated due to authorization", + "links", + ImmutableList.of( + ImmutableMap.of( + "value", + "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication", + "rel", "alternate", + "href", + "https://github.com/google/nomulus/blob/master/docs/rdap.md#authentication", + "type", "text/html"))); } diff --git a/java/google/registry/rdap/RdapJsonFormatter.java b/java/google/registry/rdap/RdapJsonFormatter.java index 707e73656..5350980db 100644 --- a/java/google/registry/rdap/RdapJsonFormatter.java +++ b/java/google/registry/rdap/RdapJsonFormatter.java @@ -272,8 +272,8 @@ public class RdapJsonFormatter { private static final ImmutableList STATUS_LIST_ACTIVE = ImmutableList.of(RdapStatus.ACTIVE.rfc7483String); - private static final ImmutableList STATUS_LIST_REMOVED = - ImmutableList.of(RdapStatus.REMOVED.rfc7483String); + private static final ImmutableList STATUS_LIST_INACTIVE = + ImmutableList.of(RdapStatus.INACTIVE.rfc7483String); private static final ImmutableMap> PHONE_TYPE_VOICE = ImmutableMap.of("type", ImmutableList.of("voice")); private static final ImmutableMap> PHONE_TYPE_FAX = @@ -496,7 +496,9 @@ public class RdapJsonFormatter { jsonBuilder.put( "status", makeStatusValueList( - domainResource.getStatusValues(), domainResource.getDeletionTime().isBefore(now))); + domainResource.getStatusValues(), + false, // isRedacted + domainResource.getDeletionTime().isBefore(now))); jsonBuilder.put("links", ImmutableList.of( makeLink("domain", domainResource.getFullyQualifiedDomainName(), linkBase))); boolean displayContacts = @@ -612,7 +614,10 @@ public class RdapJsonFormatter { } jsonBuilder.put( "status", - makeStatusValueList(statuses.build(), hostResource.getDeletionTime().isBefore(now))); + makeStatusValueList( + statuses.build(), + false, // isRedacted + hostResource.getDeletionTime().isBefore(now))); jsonBuilder.put("links", ImmutableList.of( makeLink("nameserver", hostResource.getFullyQualifiedHostName(), linkBase))); List> remarks; @@ -691,6 +696,8 @@ public class RdapJsonFormatter { DateTime now, OutputDataType outputDataType, RdapAuthorization authorization) { + boolean isAuthorized = + authorization.isAuthorizedForClientId(contactResource.getCurrentSponsorClientId()); ImmutableMap.Builder jsonBuilder = new ImmutableMap.Builder<>(); ImmutableList.Builder> remarksBuilder = new ImmutableList.Builder<>(); @@ -702,13 +709,14 @@ public class RdapJsonFormatter { isLinked(Key.create(contactResource), now) ? union(contactResource.getStatusValues(), StatusValue.LINKED) : contactResource.getStatusValues(), + !isAuthorized, contactResource.getDeletionTime().isBefore(now))); contactType.ifPresent( type -> jsonBuilder.put("roles", ImmutableList.of(convertContactTypeToRdapRole(type)))); jsonBuilder.put("links", ImmutableList.of(makeLink("entity", contactResource.getRepoId(), linkBase))); // If we are logged in as the owner of this contact, create the vCard. - if (authorization.isAuthorizedForClientId(contactResource.getCurrentSponsorClientId())) { + if (isAuthorized) { ImmutableList.Builder vcardBuilder = new ImmutableList.Builder<>(); vcardBuilder.add(VCARD_ENTRY_VERSION); PostalInfo postalInfo = contactResource.getInternationalizedPostalInfo(); @@ -794,7 +802,7 @@ public class RdapJsonFormatter { jsonBuilder.put("objectClassName", "entity"); Long ianaIdentifier = registrar.getIanaIdentifier(); jsonBuilder.put("handle", (ianaIdentifier == null) ? "(none)" : ianaIdentifier.toString()); - jsonBuilder.put("status", registrar.isLive() ? STATUS_LIST_ACTIVE : STATUS_LIST_REMOVED); + jsonBuilder.put("status", registrar.isLive() ? STATUS_LIST_ACTIVE : STATUS_LIST_INACTIVE); jsonBuilder.put("roles", ImmutableList.of(RdapEntityRole.REGISTRAR.rfc7483String)); if (ianaIdentifier != null) { jsonBuilder.put("links", @@ -1086,20 +1094,24 @@ public class RdapJsonFormatter { /** * Creates a string array of status values. * - *

The spec indicates that OK should be listed as "active". We use the "removed" status to - * indicate deleted objects. + *

The spec indicates that OK should be listed as "active". We use the "inactive" status to + * indicate deleted objects, and as directed by the profile, the "removed" status to indicate + * redacted objects. */ private static ImmutableList makeStatusValueList( - ImmutableSet statusValues, boolean isDeleted) { + ImmutableSet statusValues, boolean isRedacted, boolean isDeleted) { Stream stream = statusValues .stream() .map(status -> statusToRdapStatusMap.getOrDefault(status, RdapStatus.OBSCURED)); + if (isRedacted) { + stream = Streams.concat(stream, Stream.of(RdapStatus.REMOVED)); + } if (isDeleted) { stream = Streams.concat( stream.filter(rdapStatus -> !Objects.equals(rdapStatus, RdapStatus.ACTIVE)), - Stream.of(RdapStatus.REMOVED)); + Stream.of(RdapStatus.INACTIVE)); } return stream .map(RdapStatus::getDisplayName) diff --git a/javatests/google/registry/rdap/RdapEntityActionTest.java b/javatests/google/registry/rdap/RdapEntityActionTest.java index eebdcc8f7..82c7273bf 100644 --- a/javatests/google/registry/rdap/RdapEntityActionTest.java +++ b/javatests/google/registry/rdap/RdapEntityActionTest.java @@ -409,7 +409,7 @@ public class RdapEntityActionTest { runSuccessfulTest( deletedContact.getRepoId(), "", - "removed", + "inactive", "", false, "rdap_contact_deleted.json"); @@ -422,7 +422,7 @@ public class RdapEntityActionTest { runSuccessfulTest( deletedContact.getRepoId(), "", - "removed", + "inactive", "", false, "rdap_contact_deleted.json"); @@ -471,7 +471,7 @@ public class RdapEntityActionTest { login("deletedregistrar"); action.includeDeletedParam = Optional.of(true); runSuccessfulTest( - "104", "Yes Virginia