mirror of
https://github.com/google/nomulus.git
synced 2025-04-30 03:57:51 +02:00
Add a frontend endpoint for retrieving a domain in JSON form (#1916)
We might (likely will) modify some of the fiddly bits around this (maybe the GSON serialization, where we do the actual authorization, etc) but this should be a decent basic shell structure for endpoints that the new registrar console can call to retrieve JSON results.
This commit is contained in:
parent
e26e5adf5c
commit
b709a0ce48
12 changed files with 321 additions and 16 deletions
|
@ -94,6 +94,12 @@
|
||||||
<url-pattern>/registry-lock-verify</url-pattern>
|
<url-pattern>/registry-lock-verify</url-pattern>
|
||||||
</servlet-mapping>
|
</servlet-mapping>
|
||||||
|
|
||||||
|
<!-- Registrar console endpoints -->
|
||||||
|
<servlet-mapping>
|
||||||
|
<servlet-name>frontend-servlet</servlet-name>
|
||||||
|
<url-pattern>/console-api/*</url-pattern>
|
||||||
|
</servlet-mapping>
|
||||||
|
|
||||||
<!-- Security config -->
|
<!-- Security config -->
|
||||||
<security-constraint>
|
<security-constraint>
|
||||||
<web-resource-collection>
|
<web-resource-collection>
|
||||||
|
|
|
@ -16,6 +16,7 @@ package google.registry.model;
|
||||||
|
|
||||||
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||||
|
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
import javax.annotation.Nullable;
|
import javax.annotation.Nullable;
|
||||||
import javax.persistence.Column;
|
import javax.persistence.Column;
|
||||||
import javax.persistence.Embeddable;
|
import javax.persistence.Embeddable;
|
||||||
|
@ -28,6 +29,7 @@ import org.joda.time.DateTime;
|
||||||
public class CreateAutoTimestamp extends ImmutableObject implements UnsafeSerializable {
|
public class CreateAutoTimestamp extends ImmutableObject implements UnsafeSerializable {
|
||||||
|
|
||||||
@Column(nullable = false)
|
@Column(nullable = false)
|
||||||
|
@Expose
|
||||||
DateTime creationTime;
|
DateTime creationTime;
|
||||||
|
|
||||||
@PrePersist
|
@PrePersist
|
||||||
|
|
|
@ -31,6 +31,7 @@ import com.github.benmanes.caffeine.cache.LoadingCache;
|
||||||
import com.google.common.annotations.VisibleForTesting;
|
import com.google.common.annotations.VisibleForTesting;
|
||||||
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 com.google.gson.annotations.Expose;
|
||||||
import google.registry.config.RegistryConfig;
|
import google.registry.config.RegistryConfig;
|
||||||
import google.registry.dns.RefreshDnsAction;
|
import google.registry.dns.RefreshDnsAction;
|
||||||
import google.registry.model.eppcommon.StatusValue;
|
import google.registry.model.eppcommon.StatusValue;
|
||||||
|
@ -67,7 +68,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
|
||||||
*
|
*
|
||||||
* @see <a href="https://tools.ietf.org/html/rfc5730">RFC 5730</a>
|
* @see <a href="https://tools.ietf.org/html/rfc5730">RFC 5730</a>
|
||||||
*/
|
*/
|
||||||
@Transient String repoId;
|
@Expose @Transient String repoId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ID of the registrar that is currently sponsoring this resource.
|
* The ID of the registrar that is currently sponsoring this resource.
|
||||||
|
@ -75,7 +76,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
|
||||||
* <p>This can be null in the case of pre-Registry-3.0-migration history objects with null
|
* <p>This can be null in the case of pre-Registry-3.0-migration history objects with null
|
||||||
* resource fields.
|
* resource fields.
|
||||||
*/
|
*/
|
||||||
String currentSponsorRegistrarId;
|
@Expose String currentSponsorRegistrarId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ID of the registrar that created this resource.
|
* The ID of the registrar that created this resource.
|
||||||
|
@ -83,7 +84,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
|
||||||
* <p>This can be null in the case of pre-Registry-3.0-migration history objects with null
|
* <p>This can be null in the case of pre-Registry-3.0-migration history objects with null
|
||||||
* resource fields.
|
* resource fields.
|
||||||
*/
|
*/
|
||||||
String creationRegistrarId;
|
@Expose String creationRegistrarId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The ID of the registrar that last updated this resource.
|
* The ID of the registrar that last updated this resource.
|
||||||
|
@ -92,7 +93,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
|
||||||
* edits; it only includes EPP-visible modifications such as {@literal <update>}. Can be null if
|
* edits; it only includes EPP-visible modifications such as {@literal <update>}. Can be null if
|
||||||
* the resource has never been modified.
|
* the resource has never been modified.
|
||||||
*/
|
*/
|
||||||
String lastEppUpdateRegistrarId;
|
@Expose String lastEppUpdateRegistrarId;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The time when this resource was created.
|
* The time when this resource was created.
|
||||||
|
@ -106,6 +107,7 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
|
||||||
*/
|
*/
|
||||||
// Need to override the default non-null column attribute.
|
// Need to override the default non-null column attribute.
|
||||||
@AttributeOverride(name = "creationTime", column = @Column)
|
@AttributeOverride(name = "creationTime", column = @Column)
|
||||||
|
@Expose
|
||||||
CreateAutoTimestamp creationTime = CreateAutoTimestamp.create(null);
|
CreateAutoTimestamp creationTime = CreateAutoTimestamp.create(null);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -130,10 +132,10 @@ public abstract class EppResource extends UpdateAutoTimestampEntity implements B
|
||||||
* edits; it only includes EPP-visible modifications such as {@literal <update>}. Can be null if
|
* edits; it only includes EPP-visible modifications such as {@literal <update>}. Can be null if
|
||||||
* the resource has never been modified.
|
* the resource has never been modified.
|
||||||
*/
|
*/
|
||||||
DateTime lastEppUpdateTime;
|
@Expose DateTime lastEppUpdateTime;
|
||||||
|
|
||||||
/** Status values associated with this resource. */
|
/** Status values associated with this resource. */
|
||||||
Set<StatusValue> statuses;
|
@Expose Set<StatusValue> statuses;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When this domain/host's DNS was requested to be refreshed, or null if its DNS is up-to-date.
|
* When this domain/host's DNS was requested to be refreshed, or null if its DNS is up-to-date.
|
||||||
|
|
|
@ -40,6 +40,7 @@ import com.google.common.collect.ImmutableSet;
|
||||||
import com.google.common.collect.ImmutableSortedSet;
|
import com.google.common.collect.ImmutableSortedSet;
|
||||||
import com.google.common.collect.Ordering;
|
import com.google.common.collect.Ordering;
|
||||||
import com.google.common.collect.Sets;
|
import com.google.common.collect.Sets;
|
||||||
|
import com.google.gson.annotations.Expose;
|
||||||
import google.registry.flows.ResourceFlowUtils;
|
import google.registry.flows.ResourceFlowUtils;
|
||||||
import google.registry.model.EppResource;
|
import google.registry.model.EppResource;
|
||||||
import google.registry.model.EppResource.ResourceWithTransferData;
|
import google.registry.model.EppResource.ResourceWithTransferData;
|
||||||
|
@ -121,20 +122,20 @@ public class DomainBase extends EppResource
|
||||||
*
|
*
|
||||||
* @invariant domainName == domainName.toLowerCase(Locale.ENGLISH)
|
* @invariant domainName == domainName.toLowerCase(Locale.ENGLISH)
|
||||||
*/
|
*/
|
||||||
String domainName;
|
@Expose String domainName;
|
||||||
|
|
||||||
/** The top level domain this is under, de-normalized from {@link #domainName}. */
|
/** The top level domain this is under, de-normalized from {@link #domainName}. */
|
||||||
String tld;
|
String tld;
|
||||||
|
|
||||||
/** References to hosts that are the nameservers for the domain. */
|
/** References to hosts that are the nameservers for the domain. */
|
||||||
@Transient Set<VKey<Host>> nsHosts;
|
@Expose @Transient Set<VKey<Host>> nsHosts;
|
||||||
|
|
||||||
/** Contacts. */
|
/** Contacts. */
|
||||||
VKey<Contact> adminContact;
|
@Expose VKey<Contact> adminContact;
|
||||||
|
|
||||||
VKey<Contact> billingContact;
|
@Expose VKey<Contact> billingContact;
|
||||||
VKey<Contact> techContact;
|
@Expose VKey<Contact> techContact;
|
||||||
VKey<Contact> registrantContact;
|
@Expose VKey<Contact> registrantContact;
|
||||||
|
|
||||||
/** Authorization info (aka transfer secret) of the domain. */
|
/** Authorization info (aka transfer secret) of the domain. */
|
||||||
@Embedded
|
@Embedded
|
||||||
|
@ -175,10 +176,10 @@ public class DomainBase extends EppResource
|
||||||
String idnTableName;
|
String idnTableName;
|
||||||
|
|
||||||
/** Fully qualified host names of this domain's active subordinate hosts. */
|
/** Fully qualified host names of this domain's active subordinate hosts. */
|
||||||
Set<String> subordinateHosts;
|
@Expose Set<String> subordinateHosts;
|
||||||
|
|
||||||
/** When this domain's registration will expire. */
|
/** When this domain's registration will expire. */
|
||||||
DateTime registrationExpirationTime;
|
@Expose DateTime registrationExpirationTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The poll message associated with this domain being deleted.
|
* The poll message associated with this domain being deleted.
|
||||||
|
@ -230,7 +231,7 @@ public class DomainBase extends EppResource
|
||||||
*
|
*
|
||||||
* <p>Can be null if the resource has never been transferred.
|
* <p>Can be null if the resource has never been transferred.
|
||||||
*/
|
*/
|
||||||
DateTime lastTransferTime;
|
@Expose DateTime lastTransferTime;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When the domain's autorenewal status will expire.
|
* When the domain's autorenewal status will expire.
|
||||||
|
|
|
@ -25,6 +25,7 @@ import google.registry.monitoring.whitebox.WhiteboxModule;
|
||||||
import google.registry.request.RequestComponentBuilder;
|
import google.registry.request.RequestComponentBuilder;
|
||||||
import google.registry.request.RequestModule;
|
import google.registry.request.RequestModule;
|
||||||
import google.registry.request.RequestScope;
|
import google.registry.request.RequestScope;
|
||||||
|
import google.registry.ui.server.console.ConsoleDomainGetAction;
|
||||||
import google.registry.ui.server.registrar.ConsoleOteSetupAction;
|
import google.registry.ui.server.registrar.ConsoleOteSetupAction;
|
||||||
import google.registry.ui.server.registrar.ConsoleRegistrarCreatorAction;
|
import google.registry.ui.server.registrar.ConsoleRegistrarCreatorAction;
|
||||||
import google.registry.ui.server.registrar.ConsoleUiAction;
|
import google.registry.ui.server.registrar.ConsoleUiAction;
|
||||||
|
@ -61,6 +62,8 @@ interface FrontendRequestComponent {
|
||||||
|
|
||||||
RegistryLockVerifyAction registryLockVerifyAction();
|
RegistryLockVerifyAction registryLockVerifyAction();
|
||||||
|
|
||||||
|
ConsoleDomainGetAction consoleDomainGetAction();
|
||||||
|
|
||||||
@Subcomponent.Builder
|
@Subcomponent.Builder
|
||||||
abstract class Builder implements RequestComponentBuilder<FrontendRequestComponent> {
|
abstract class Builder implements RequestComponentBuilder<FrontendRequestComponent> {
|
||||||
@Override public abstract Builder requestModule(RequestModule requestModule);
|
@Override public abstract Builder requestModule(RequestModule requestModule);
|
||||||
|
|
|
@ -22,6 +22,7 @@ import com.google.common.base.Joiner;
|
||||||
import com.google.common.base.Splitter;
|
import com.google.common.base.Splitter;
|
||||||
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.gson.annotations.Expose;
|
||||||
import google.registry.model.EppResource;
|
import google.registry.model.EppResource;
|
||||||
import google.registry.model.ImmutableObject;
|
import google.registry.model.ImmutableObject;
|
||||||
import google.registry.model.contact.Contact;
|
import google.registry.model.contact.Contact;
|
||||||
|
@ -52,7 +53,7 @@ public class VKey<T> extends ImmutableObject implements Serializable {
|
||||||
.collect(toImmutableMap(Class::getSimpleName, identity()));
|
.collect(toImmutableMap(Class::getSimpleName, identity()));
|
||||||
|
|
||||||
// The primary key for the referenced entity.
|
// The primary key for the referenced entity.
|
||||||
Serializable key;
|
@Expose Serializable key;
|
||||||
|
|
||||||
Class<? extends T> kind;
|
Class<? extends T> kind;
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,91 @@
|
||||||
|
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package google.registry.ui.server.console;
|
||||||
|
|
||||||
|
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
|
||||||
|
|
||||||
|
import com.google.api.client.http.HttpStatusCodes;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import google.registry.model.EppResourceUtils;
|
||||||
|
import google.registry.model.console.ConsolePermission;
|
||||||
|
import google.registry.model.console.User;
|
||||||
|
import google.registry.model.domain.Domain;
|
||||||
|
import google.registry.request.Action;
|
||||||
|
import google.registry.request.Parameter;
|
||||||
|
import google.registry.request.Response;
|
||||||
|
import google.registry.request.auth.Auth;
|
||||||
|
import google.registry.request.auth.AuthResult;
|
||||||
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
|
import google.registry.ui.server.registrar.JsonGetAction;
|
||||||
|
import java.util.Optional;
|
||||||
|
import javax.inject.Inject;
|
||||||
|
|
||||||
|
/** Returns a JSON representation of a domain to the registrar console. */
|
||||||
|
@Action(
|
||||||
|
service = Action.Service.DEFAULT,
|
||||||
|
path = ConsoleDomainGetAction.PATH,
|
||||||
|
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
|
||||||
|
public class ConsoleDomainGetAction implements JsonGetAction {
|
||||||
|
|
||||||
|
public static final String PATH = "/console-api/domain";
|
||||||
|
|
||||||
|
private final AuthResult authResult;
|
||||||
|
private final Response response;
|
||||||
|
private final Gson gson;
|
||||||
|
private final String paramDomain;
|
||||||
|
|
||||||
|
@Inject
|
||||||
|
public ConsoleDomainGetAction(
|
||||||
|
AuthResult authResult,
|
||||||
|
Response response,
|
||||||
|
Gson gson,
|
||||||
|
@Parameter("domain") String paramDomain) {
|
||||||
|
this.authResult = authResult;
|
||||||
|
this.response = response;
|
||||||
|
this.gson = gson;
|
||||||
|
this.paramDomain = paramDomain;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (!authResult.isAuthenticated() || !authResult.userAuthInfo().isPresent()) {
|
||||||
|
response.setStatus(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
UserAuthInfo authInfo = authResult.userAuthInfo().get();
|
||||||
|
if (!authInfo.consoleUser().isPresent()) {
|
||||||
|
response.setStatus(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
User user = authInfo.consoleUser().get();
|
||||||
|
Optional<Domain> possibleDomain =
|
||||||
|
tm().transact(
|
||||||
|
() ->
|
||||||
|
EppResourceUtils.loadByForeignKeyCached(
|
||||||
|
Domain.class, paramDomain, tm().getTransactionTime()));
|
||||||
|
if (!possibleDomain.isPresent()) {
|
||||||
|
response.setStatus(HttpStatusCodes.STATUS_CODE_NOT_FOUND);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
Domain domain = possibleDomain.get();
|
||||||
|
if (!user.getUserRoles()
|
||||||
|
.hasPermission(domain.getCurrentSponsorRegistrarId(), ConsolePermission.DOWNLOAD_DOMAINS)) {
|
||||||
|
response.setStatus(HttpStatusCodes.STATUS_CODE_NOT_FOUND);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
response.setStatus(HttpStatusCodes.STATUS_CODE_OK);
|
||||||
|
response.setPayload(gson.toJson(domain));
|
||||||
|
}
|
||||||
|
}
|
|
@ -156,4 +156,10 @@ public final class RegistrarConsoleModule {
|
||||||
static Boolean provideIsLock(HttpServletRequest req) {
|
static Boolean provideIsLock(HttpServletRequest req) {
|
||||||
return extractBooleanParameter(req, "isLock");
|
return extractBooleanParameter(req, "isLock");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Provides
|
||||||
|
@Parameter("domain")
|
||||||
|
static String provideDomain(HttpServletRequest req) {
|
||||||
|
return extractRequiredParameter(req, "domain");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,139 @@
|
||||||
|
// Copyright 2023 The Nomulus Authors. All Rights Reserved.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
package google.registry.ui.server.console;
|
||||||
|
|
||||||
|
import static com.google.common.truth.Truth.assertThat;
|
||||||
|
import static google.registry.testing.DatabaseHelper.createTld;
|
||||||
|
import static org.mockito.Mockito.mock;
|
||||||
|
|
||||||
|
import com.google.api.client.http.HttpStatusCodes;
|
||||||
|
import com.google.common.collect.ImmutableMap;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import google.registry.model.console.RegistrarRole;
|
||||||
|
import google.registry.model.console.User;
|
||||||
|
import google.registry.model.console.UserRoles;
|
||||||
|
import google.registry.persistence.transaction.JpaTestExtensions;
|
||||||
|
import google.registry.request.auth.AuthLevel;
|
||||||
|
import google.registry.request.auth.AuthResult;
|
||||||
|
import google.registry.request.auth.UserAuthInfo;
|
||||||
|
import google.registry.testing.DatabaseHelper;
|
||||||
|
import google.registry.testing.FakeResponse;
|
||||||
|
import google.registry.util.UtilsModule;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.RegisterExtension;
|
||||||
|
|
||||||
|
/** Tests for {@link google.registry.ui.server.console.ConsoleDomainGetAction}. */
|
||||||
|
public class ConsoleDomainGetActionTest {
|
||||||
|
|
||||||
|
private static final Gson GSON = UtilsModule.provideGson();
|
||||||
|
private static final FakeResponse RESPONSE = new FakeResponse();
|
||||||
|
|
||||||
|
@RegisterExtension
|
||||||
|
final JpaTestExtensions.JpaIntegrationTestExtension jpa =
|
||||||
|
new JpaTestExtensions.Builder().buildIntegrationTestExtension();
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void beforeEach() {
|
||||||
|
createTld("tld");
|
||||||
|
DatabaseHelper.persistActiveDomain("exists.tld");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testSuccess_fullJsonRepresentation() {
|
||||||
|
ConsoleDomainGetAction action =
|
||||||
|
createAction(
|
||||||
|
AuthResult.create(
|
||||||
|
AuthLevel.USER,
|
||||||
|
UserAuthInfo.create(
|
||||||
|
createUser(
|
||||||
|
new UserRoles.Builder()
|
||||||
|
.setRegistrarRoles(
|
||||||
|
ImmutableMap.of("TheRegistrar", RegistrarRole.ACCOUNT_MANAGER))
|
||||||
|
.build()))),
|
||||||
|
"exists.tld");
|
||||||
|
action.run();
|
||||||
|
assertThat(RESPONSE.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_OK);
|
||||||
|
assertThat(RESPONSE.getPayload())
|
||||||
|
.isEqualTo(
|
||||||
|
"{\"domainName\":\"exists.tld\",\"adminContact\":{\"key\":\"3-ROID\"},\"techContact\":"
|
||||||
|
+ "{\"key\":\"3-ROID\"},\"registrantContact\":{\"key\":\"3-ROID\"},\"registrationExpirationTime\":"
|
||||||
|
+ "\"294247-01-10T04:00:54.775Z\",\"lastTransferTime\":\"null\",\"repoId\":\"2-TLD\","
|
||||||
|
+ "\"currentSponsorRegistrarId\":\"TheRegistrar\",\"creationRegistrarId\":\"TheRegistrar\","
|
||||||
|
+ "\"creationTime\":{\"creationTime\":\"1970-01-01T00:00:00.000Z\"},\"lastEppUpdateTime\":\"null\","
|
||||||
|
+ "\"statuses\":[\"INACTIVE\"]}");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFailure_emptyAuth() {
|
||||||
|
ConsoleDomainGetAction action = createAction(AuthResult.NOT_AUTHENTICATED, "exists.tld");
|
||||||
|
action.run();
|
||||||
|
assertThat(RESPONSE.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFailure_appAuth() {
|
||||||
|
ConsoleDomainGetAction action = createAction(AuthResult.create(AuthLevel.APP), "exists.tld");
|
||||||
|
action.run();
|
||||||
|
assertThat(RESPONSE.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFailure_wrongTypeOfUser() {
|
||||||
|
ConsoleDomainGetAction action =
|
||||||
|
createAction(
|
||||||
|
AuthResult.create(
|
||||||
|
AuthLevel.USER,
|
||||||
|
UserAuthInfo.create(mock(com.google.appengine.api.users.User.class), false)),
|
||||||
|
"exists.tld");
|
||||||
|
action.run();
|
||||||
|
assertThat(RESPONSE.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFailure_noAccessToRegistrar() {
|
||||||
|
ConsoleDomainGetAction action =
|
||||||
|
createAction(
|
||||||
|
AuthResult.create(
|
||||||
|
AuthLevel.USER, UserAuthInfo.create(createUser(new UserRoles.Builder().build()))),
|
||||||
|
"exists.tld");
|
||||||
|
action.run();
|
||||||
|
assertThat(RESPONSE.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void testFailure_nonexistentDomain() {
|
||||||
|
ConsoleDomainGetAction action =
|
||||||
|
createAction(
|
||||||
|
AuthResult.create(
|
||||||
|
AuthLevel.USER,
|
||||||
|
UserAuthInfo.create(createUser(new UserRoles.Builder().setIsAdmin(true).build()))),
|
||||||
|
"nonexistent.tld");
|
||||||
|
action.run();
|
||||||
|
assertThat(RESPONSE.getStatus()).isEqualTo(HttpStatusCodes.STATUS_CODE_NOT_FOUND);
|
||||||
|
}
|
||||||
|
|
||||||
|
private User createUser(UserRoles userRoles) {
|
||||||
|
return new User.Builder()
|
||||||
|
.setEmailAddress("email@email.com")
|
||||||
|
.setGaiaId("gaiaId")
|
||||||
|
.setUserRoles(userRoles)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ConsoleDomainGetAction createAction(AuthResult authResult, String domain) {
|
||||||
|
return new ConsoleDomainGetAction(authResult, RESPONSE, GSON, domain);
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,5 +1,6 @@
|
||||||
PATH CLASS METHODS OK AUTH_METHODS MIN USER_POLICY
|
PATH CLASS METHODS OK AUTH_METHODS MIN USER_POLICY
|
||||||
/_dr/epp EppTlsAction POST n INTERNAL,API APP PUBLIC
|
/_dr/epp EppTlsAction POST n INTERNAL,API APP PUBLIC
|
||||||
|
/console-api/domain ConsoleDomainGetAction GET n API,LEGACY USER PUBLIC
|
||||||
/registrar ConsoleUiAction GET n INTERNAL,API,LEGACY NONE PUBLIC
|
/registrar ConsoleUiAction GET n INTERNAL,API,LEGACY NONE PUBLIC
|
||||||
/registrar-create ConsoleRegistrarCreatorAction POST,GET n INTERNAL,API,LEGACY NONE PUBLIC
|
/registrar-create ConsoleRegistrarCreatorAction POST,GET n INTERNAL,API,LEGACY NONE PUBLIC
|
||||||
/registrar-ote-setup ConsoleOteSetupAction POST,GET n INTERNAL,API,LEGACY NONE PUBLIC
|
/registrar-ote-setup ConsoleOteSetupAction POST,GET n INTERNAL,API,LEGACY NONE PUBLIC
|
||||||
|
|
|
@ -0,0 +1,41 @@
|
||||||
|
// Copyright 2023 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.util;
|
||||||
|
|
||||||
|
import com.google.gson.TypeAdapter;
|
||||||
|
import com.google.gson.stream.JsonReader;
|
||||||
|
import com.google.gson.stream.JsonWriter;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Objects;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
import org.joda.time.format.ISODateTimeFormat;
|
||||||
|
|
||||||
|
/** GSON type adapter for Joda {@link DateTime} objects. */
|
||||||
|
public class DateTimeTypeAdapter extends TypeAdapter<DateTime> {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void write(JsonWriter out, DateTime value) throws IOException {
|
||||||
|
out.value(Objects.toString(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public DateTime read(JsonReader in) throws IOException {
|
||||||
|
String stringValue = in.nextString();
|
||||||
|
if (stringValue.equals("null")) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return ISODateTimeFormat.dateTime().withZoneUTC().parseDateTime(stringValue);
|
||||||
|
}
|
||||||
|
}
|
|
@ -16,6 +16,8 @@ package google.registry.util;
|
||||||
|
|
||||||
import com.google.appengine.api.modules.ModulesService;
|
import com.google.appengine.api.modules.ModulesService;
|
||||||
import com.google.appengine.api.modules.ModulesServiceFactory;
|
import com.google.appengine.api.modules.ModulesServiceFactory;
|
||||||
|
import com.google.gson.Gson;
|
||||||
|
import com.google.gson.GsonBuilder;
|
||||||
import dagger.Binds;
|
import dagger.Binds;
|
||||||
import dagger.Module;
|
import dagger.Module;
|
||||||
import dagger.Provides;
|
import dagger.Provides;
|
||||||
|
@ -25,6 +27,7 @@ import java.security.SecureRandom;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
import javax.inject.Named;
|
import javax.inject.Named;
|
||||||
import javax.inject.Singleton;
|
import javax.inject.Singleton;
|
||||||
|
import org.joda.time.DateTime;
|
||||||
|
|
||||||
/** Dagger module to provide instances of various utils classes. */
|
/** Dagger module to provide instances of various utils classes. */
|
||||||
@Module
|
@Module
|
||||||
|
@ -83,4 +86,13 @@ public abstract class UtilsModule {
|
||||||
public static StringGenerator provideDigitsOnlyStringGenerator(SecureRandom secureRandom) {
|
public static StringGenerator provideDigitsOnlyStringGenerator(SecureRandom secureRandom) {
|
||||||
return new RandomStringGenerator(StringGenerator.Alphabets.DIGITS_ONLY, secureRandom);
|
return new RandomStringGenerator(StringGenerator.Alphabets.DIGITS_ONLY, secureRandom);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Singleton
|
||||||
|
@Provides
|
||||||
|
public static Gson provideGson() {
|
||||||
|
return new GsonBuilder()
|
||||||
|
.registerTypeAdapter(DateTime.class, new DateTimeTypeAdapter())
|
||||||
|
.excludeFieldsWithoutExposeAnnotation()
|
||||||
|
.create();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue