1
0
mirror of https://github.com/google/nomulus synced 2026-07-10 18:13:02 +00:00

Compare commits

...

17 Commits

Author SHA1 Message Date
Shicong Huang b9c40648d0 Add dual write for Registrar (#474)
* Add dual write for Registrar

* Use @AlsoLoad to set street field for Cloud SQL

* Change email body to use the new streetLine field

* Refactored the logic to handle street fields

* Simplify postLoad function

* Address comments

* Add a TODO to remove street

* Add test for onLoad and postLoad

* Rebase on master
2020-02-13 16:00:21 -05:00
sarahcaseybot 22a879e655 Add the schema and DAO for Locks in CloudSQL (#462)
* Add the schema and DAO for Locks in CloudSQL

* Addresses some comments

* Change number on flyway file

* Small changes

* More small changes

* Use checkArgumentNotNull instead of checkNotNull

* Address comments

* fix javadocs

* update persistence
2020-02-13 10:22:10 -05:00
Weimin Yu 62433c2238 Use JSON API for Maven Repo on GCS (#483)
* Use JSON API for Maven Repo on GCS

The url pattern https://storage.googleapis.com/{Bucket}/{Path}
uses the legacy XML API, which seems to be less robust than
the JSON API. We have observed connection resets after a few
thousand-file download bursts over 30 minutes.

This PR changes all urls to registry's Maven repo on GCS to
gcs://{Bucket}/{Path}. Gradle uses the JSON API for such urls.

TESTED=In Cloud Build with local change
2020-02-12 14:03:50 -05:00
Shicong Huang 90945bcc30 Add a test to verify persistence.xml (#482) 2020-02-12 12:39:03 -05:00
Weimin Yu f134c4bf37 Use dependency cache in all Gradle tasks in GCB (#481)
* Use dependency cache in all Gradle tasks in GCB

Make the initial test and the final publishing steps use the shared
dependency cache.

Also make the initial test use the registry's own maven repo instead
of Maven Central.
2020-02-11 14:50:22 -05:00
gbrodman 44921c29d6 Clean up RegistryLockPostAction (#470)
* Clean up RegistryLockPostAction

* pocId -> userEmail when appropriate

* Merge remote-tracking branch 'origin/master' into lockPostImprovements

* Remove pocId
2020-02-11 08:43:44 -07:00
Weimin Yu ce80278ab7 Make Gradle dependency cache shareable in GCB (#479)
* Make Gradle dependency cache shareable in GCB

Make Gradle put its caches in the source tree so that
they can be preserved across steps. When left at their
default location, caches are lost after each step.
2020-02-10 11:20:11 -05:00
Shicong Huang 594ce30122 Auto-apply JPA converters for collection type (#469)
* Auto-apply JPA converters for collection type

* Extract common logic to a base class

* Remove extra lines

* Rebase on master
2020-02-10 10:33:43 -05:00
Weimin Yu 736f788eea Use CA cert in tests (#475)
* Use CA cert in tests

Our tests were using a self-signed cert created by a netty utility.
That cert is not CA, and cannot be used with newer JDK versions
(starting from u242 with Ubuntu openjdk).

Now we generate a unsafe cert for tests. The new cert,
SelfSignedCaCertificate, needs to be made test-only.
To do so we need to refactor both prober and proxy.
2020-02-07 10:23:24 -05:00
Shicong Huang d6f49f5c08 Add JPA annotations to RegistrarContact (#432) 2020-02-06 16:58:15 -05:00
Ben McIlwain 8b9139bc4c Always attempt to save the claims list to Cloud SQL (#472)
* Always attempt to save the claims list to Cloud SQL
2020-02-06 12:21:34 -05:00
Ben McIlwain b148102716 Always save reserved lists to Cloud SQL (#471)
* Always save reserved lists to Cloud SQL

Otherwise it's too easy to forget to run this additional option, and then things will
fall out of sync and start throwing errors.
2020-02-06 12:21:26 -05:00
Shicong Huang 9ea06ebf35 Use JPA @Enumerated to convert enum to string (#466) 2020-02-04 10:50:03 -05:00
gbrodman c0afb9aeee Use randomly-generated base-58 strings for RegistryLock verification codes (#464)
* Use randomly-generated strings for RegistryLock verification codes

We were using UUIDs before which are also fine, but unnecessarily long.
The RegistryLock class itself does not enforce any particular format for
the lock verification codes.
2020-02-03 13:50:54 -05:00
Michael Muller 76d8afe856 Implement dump_golden_schema command in devtool (#467)
* Implement dump_golden_schema command in devtool

Add a dump_golden_schema command so that we can generate the golden schema
in-place without having to do the test -> fail -> copy -> test dance.

Refactor the SQL container functionality from GenerateSqlCommand.  There is
some duplication of code between the dump command and SchemaTest which should
be dealt with in a subsequent PR.

* Reformatted and changes in response to review

* Fix getDockerTag() usage

* Fix "leaked resource"
2020-02-03 13:25:27 -05:00
gbrodman 36787c37fb Add a RegistryLockPostAction and tests (#459)
* Add a RegistryLockPostAction and tests

* Response to CR and more robust email content test

* Fix typo

* Run save + email in a JPA transaction

* Use action in subject
2020-02-03 11:34:01 -05:00
Weimin Yu 36e46097e3 Allow non-CA cert as trust anchor in tests (#468)
* Allow non-CA cert as trust anchor in tests

Stay with the legacy behavior to unblock release build.
We will update the test cert generation code later.

TESTED=reproduced and fixed test failures in builder container
2020-02-03 11:02:52 -05:00
138 changed files with 3366 additions and 1315 deletions
+1
View File
@@ -97,6 +97,7 @@ nomulus.iws
!/gradle/wrapper/**/*.jar
.gradle/
**/build
cloudbuild-caches/
node_modules/**
/repos/
+1 -1
View File
@@ -22,7 +22,7 @@ import sys
import re
# We should never analyze any generated files
UNIVERSALLY_SKIPPED_PATTERNS = {"/build/", "/out/"}
UNIVERSALLY_SKIPPED_PATTERNS = {"/build/", "cloudbuild-caches", "/out/"}
# We can't rely on CI to have the Enum package installed so we do this instead.
FORBIDDEN = 1
REQUIRED = 2
+11 -2
View File
@@ -52,9 +52,11 @@ def outcastTestPatterns = [
def dockerIncompatibleTestPatterns = [
// The webdriver tests start headless Chrome in a Docker container,
// resulting in Docker-in-Docker complications. Likewise,
// GenerateSqlSchemaCommandTest launches postgresql in a docker container.
// GenerateSqlSchemaCommandTest and DumpGoldenSchemaCommandTest launch
// postgresql in a docker container.
"google/registry/webdriver/*",
"google/registry/tools/GenerateSqlSchemaCommandTest.*",
"google/registry/tools/DumpGoldenSchemaCommandTest.*",
// PathParameterTest includes tests which validate that file permissions are
// respected. However when running in Docker the user is root by default, so
// every file is read/write-able. There is no way to exclude specific test
@@ -93,7 +95,11 @@ sourceSets {
nonprod {
java {
compileClasspath += main.output
runtimeClasspath += main.output
// Add the DB runtime classpath to nonprod so we can load the flyway
// scripts.
runtimeClasspath += main.output +
rootProject.project(":db").sourceSets.main.runtimeClasspath
}
}
test {
@@ -321,6 +327,9 @@ dependencies {
// Tool dependencies. used for doc generation.
compile files("${System.properties['java.home']}/../lib/tools.jar")
// Flyway classes needed to generate the golden file.
compile deps['org.flywaydb:flyway-core']
closureCompiler deps['com.google.javascript:closure-compiler']
}
+15 -14
View File
@@ -10,11 +10,11 @@ com.fasterxml.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
com.google.api-client:google-api-client-appengine:1.29.0
com.google.api-client:google-api-client-appengine:1.30.7
com.google.api-client:google-api-client-jackson2:1.27.0
com.google.api-client:google-api-client-java6:1.27.0
com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api-client:google-api-client-servlet:1.30.7
com.google.api-client:google-api-client:1.30.7
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
@@ -84,22 +84,22 @@ com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.8.2
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-appengine:1.34.0
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.30.1
com.google.http-client:google-http-client:1.34.0
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
com.google.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:metrics:1.0.7
com.google.monitoring-client:stackdriver:1.0.7
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-appengine:1.30.5
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.oauth-client:google-oauth-client-servlet:1.30.5
com.google.oauth-client:google-oauth-client:1.30.5
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -124,7 +124,7 @@ io.dropwizard.metrics:metrics-core:3.1.2
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-context:1.22.1
io.grpc:grpc-core:1.17.1
io.grpc:grpc-grpclb:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
@@ -146,10 +146,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.21.0
io.opencensus:opencensus-contrib-http-util:0.24.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -183,8 +183,8 @@ org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-lang3:3.5
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.apache.httpcomponents:httpclient:4.5.10
org.apache.httpcomponents:httpcore:4.4.12
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
@@ -193,6 +193,7 @@ org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.dom4j:dom4j:2.1.1
org.easymock:easymock:3.0
org.flywaydb:flyway-core:5.2.4
org.glassfish.jaxb:jaxb-runtime:2.3.1
org.glassfish.jaxb:txw2:2.3.1
org.hamcrest:hamcrest-core:1.3
@@ -10,11 +10,11 @@ com.fasterxml.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
com.google.api-client:google-api-client-appengine:1.29.0
com.google.api-client:google-api-client-appengine:1.30.7
com.google.api-client:google-api-client-jackson2:1.27.0
com.google.api-client:google-api-client-java6:1.27.0
com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api-client:google-api-client-servlet:1.30.7
com.google.api-client:google-api-client:1.30.7
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
@@ -83,22 +83,22 @@ com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.8.2
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-appengine:1.34.0
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.30.1
com.google.http-client:google-http-client:1.34.0
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
com.google.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:metrics:1.0.7
com.google.monitoring-client:stackdriver:1.0.7
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-appengine:1.30.5
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.oauth-client:google-oauth-client-servlet:1.30.5
com.google.oauth-client:google-oauth-client:1.30.5
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -123,7 +123,7 @@ io.dropwizard.metrics:metrics-core:3.1.2
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-context:1.22.1
io.grpc:grpc-core:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
io.grpc:grpc-netty:1.17.1
@@ -144,10 +144,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.21.0
io.opencensus:opencensus-contrib-http-util:0.24.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -180,8 +180,8 @@ org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-lang3:3.5
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.apache.httpcomponents:httpclient:4.5.10
org.apache.httpcomponents:httpcore:4.4.12
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
@@ -190,6 +190,7 @@ org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.dom4j:dom4j:2.1.1
org.easymock:easymock:3.0
org.flywaydb:flyway-core:5.2.4
org.glassfish.jaxb:jaxb-runtime:2.3.1
org.glassfish.jaxb:txw2:2.3.1
org.hibernate.common:hibernate-commons-annotations:5.1.0.Final
+15 -14
View File
@@ -18,11 +18,11 @@ com.github.jnr:jnr-ffi:2.1.9
com.github.jnr:jnr-posix:3.0.47
com.github.jnr:jnr-unixsocket:0.21
com.github.jnr:jnr-x86asm:1.0.2
com.google.api-client:google-api-client-appengine:1.29.0
com.google.api-client:google-api-client-appengine:1.30.7
com.google.api-client:google-api-client-jackson2:1.27.0
com.google.api-client:google-api-client-java6:1.27.0
com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api-client:google-api-client-servlet:1.30.7
com.google.api-client:google-api-client:1.30.7
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
@@ -95,22 +95,22 @@ com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.8.2
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-appengine:1.34.0
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.30.1
com.google.http-client:google-http-client:1.34.0
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
com.google.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:metrics:1.0.7
com.google.monitoring-client:stackdriver:1.0.7
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-appengine:1.30.5
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.oauth-client:google-oauth-client-servlet:1.30.5
com.google.oauth-client:google-oauth-client:1.30.5
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -135,7 +135,7 @@ io.dropwizard.metrics:metrics-core:3.1.2
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-context:1.22.1
io.grpc:grpc-core:1.17.1
io.grpc:grpc-grpclb:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
@@ -157,10 +157,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.21.0
io.opencensus:opencensus-contrib-http-util:0.24.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -194,8 +194,8 @@ org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-lang3:3.5
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.apache.httpcomponents:httpclient:4.5.10
org.apache.httpcomponents:httpcore:4.4.12
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
@@ -204,6 +204,7 @@ org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.dom4j:dom4j:2.1.1
org.easymock:easymock:3.0
org.flywaydb:flyway-core:5.2.4
org.glassfish.jaxb:jaxb-runtime:2.3.1
org.glassfish.jaxb:txw2:2.3.1
org.hamcrest:hamcrest-core:1.3
@@ -18,11 +18,11 @@ com.github.jnr:jnr-ffi:2.1.9
com.github.jnr:jnr-posix:3.0.47
com.github.jnr:jnr-unixsocket:0.21
com.github.jnr:jnr-x86asm:1.0.2
com.google.api-client:google-api-client-appengine:1.29.0
com.google.api-client:google-api-client-appengine:1.30.7
com.google.api-client:google-api-client-jackson2:1.27.0
com.google.api-client:google-api-client-java6:1.27.0
com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api-client:google-api-client-servlet:1.30.7
com.google.api-client:google-api-client:1.30.7
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
@@ -95,22 +95,22 @@ com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.8.2
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-appengine:1.34.0
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.30.1
com.google.http-client:google-http-client:1.34.0
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
com.google.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:metrics:1.0.7
com.google.monitoring-client:stackdriver:1.0.7
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-appengine:1.30.5
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.oauth-client:google-oauth-client-servlet:1.30.5
com.google.oauth-client:google-oauth-client:1.30.5
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -135,7 +135,7 @@ io.dropwizard.metrics:metrics-core:3.1.2
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-context:1.22.1
io.grpc:grpc-core:1.17.1
io.grpc:grpc-grpclb:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
@@ -157,10 +157,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.21.0
io.opencensus:opencensus-contrib-http-util:0.24.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -193,8 +193,8 @@ org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-lang3:3.5
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.apache.httpcomponents:httpclient:4.5.10
org.apache.httpcomponents:httpcore:4.4.12
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
@@ -203,6 +203,7 @@ org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.dom4j:dom4j:2.1.1
org.easymock:easymock:3.0
org.flywaydb:flyway-core:5.2.4
org.glassfish.jaxb:jaxb-runtime:2.3.1
org.glassfish.jaxb:txw2:2.3.1
org.hibernate.common:hibernate-commons-annotations:5.1.0.Final
@@ -10,11 +10,11 @@ com.fasterxml.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
com.google.api-client:google-api-client-appengine:1.29.0
com.google.api-client:google-api-client-appengine:1.30.7
com.google.api-client:google-api-client-jackson2:1.27.0
com.google.api-client:google-api-client-java6:1.27.0
com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api-client:google-api-client-servlet:1.30.7
com.google.api-client:google-api-client:1.30.7
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
@@ -84,22 +84,22 @@ com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.8.2
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-appengine:1.34.0
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.30.1
com.google.http-client:google-http-client:1.34.0
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
com.google.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:metrics:1.0.7
com.google.monitoring-client:stackdriver:1.0.7
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-appengine:1.30.5
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.oauth-client:google-oauth-client-servlet:1.30.5
com.google.oauth-client:google-oauth-client:1.30.5
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -124,7 +124,7 @@ io.dropwizard.metrics:metrics-core:3.1.2
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-context:1.22.1
io.grpc:grpc-core:1.17.1
io.grpc:grpc-grpclb:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
@@ -146,10 +146,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.21.0
io.opencensus:opencensus-contrib-http-util:0.24.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -183,8 +183,8 @@ org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-lang3:3.5
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.apache.httpcomponents:httpclient:4.5.10
org.apache.httpcomponents:httpcore:4.4.12
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
@@ -193,6 +193,7 @@ org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.dom4j:dom4j:2.1.1
org.easymock:easymock:3.0
org.flywaydb:flyway-core:5.2.4
org.glassfish.jaxb:jaxb-runtime:2.3.1
org.glassfish.jaxb:txw2:2.3.1
org.hamcrest:hamcrest-core:1.3
@@ -10,11 +10,11 @@ com.fasterxml.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
com.google.api-client:google-api-client-appengine:1.29.0
com.google.api-client:google-api-client-appengine:1.30.7
com.google.api-client:google-api-client-jackson2:1.27.0
com.google.api-client:google-api-client-java6:1.27.0
com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api-client:google-api-client-servlet:1.30.7
com.google.api-client:google-api-client:1.30.7
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
@@ -83,22 +83,22 @@ com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.8.2
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-appengine:1.34.0
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.30.1
com.google.http-client:google-http-client:1.34.0
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
com.google.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:metrics:1.0.7
com.google.monitoring-client:stackdriver:1.0.7
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-appengine:1.30.5
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.oauth-client:google-oauth-client-servlet:1.30.5
com.google.oauth-client:google-oauth-client:1.30.5
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -123,7 +123,7 @@ io.dropwizard.metrics:metrics-core:3.1.2
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-context:1.22.1
io.grpc:grpc-core:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
io.grpc:grpc-netty:1.17.1
@@ -144,10 +144,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.21.0
io.opencensus:opencensus-contrib-http-util:0.24.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -181,8 +181,8 @@ org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-lang3:3.5
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.apache.httpcomponents:httpclient:4.5.10
org.apache.httpcomponents:httpcore:4.4.12
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
@@ -191,6 +191,7 @@ org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.dom4j:dom4j:2.1.1
org.easymock:easymock:3.0
org.flywaydb:flyway-core:5.2.4
org.glassfish.jaxb:jaxb-runtime:2.3.1
org.glassfish.jaxb:txw2:2.3.1
org.hamcrest:hamcrest-core:1.3
@@ -10,11 +10,11 @@ com.fasterxml.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
com.google.api-client:google-api-client-appengine:1.29.0
com.google.api-client:google-api-client-appengine:1.30.7
com.google.api-client:google-api-client-jackson2:1.27.0
com.google.api-client:google-api-client-java6:1.27.0
com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api-client:google-api-client-servlet:1.30.7
com.google.api-client:google-api-client:1.30.7
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
@@ -84,22 +84,22 @@ com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.8.2
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-appengine:1.34.0
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.30.1
com.google.http-client:google-http-client:1.34.0
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
com.google.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:metrics:1.0.7
com.google.monitoring-client:stackdriver:1.0.7
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-appengine:1.30.5
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.oauth-client:google-oauth-client-servlet:1.30.5
com.google.oauth-client:google-oauth-client:1.30.5
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -124,7 +124,7 @@ io.dropwizard.metrics:metrics-core:3.1.2
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-context:1.22.1
io.grpc:grpc-core:1.17.1
io.grpc:grpc-grpclb:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
@@ -146,10 +146,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.21.0
io.opencensus:opencensus-contrib-http-util:0.24.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -183,8 +183,8 @@ org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-lang3:3.5
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.apache.httpcomponents:httpclient:4.5.10
org.apache.httpcomponents:httpcore:4.4.12
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
@@ -193,6 +193,7 @@ org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.dom4j:dom4j:2.1.1
org.easymock:easymock:3.0
org.flywaydb:flyway-core:5.2.4
org.glassfish.jaxb:jaxb-runtime:2.3.1
org.glassfish.jaxb:txw2:2.3.1
org.hamcrest:hamcrest-core:1.3
@@ -10,11 +10,11 @@ com.fasterxml.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
com.google.api-client:google-api-client-appengine:1.29.0
com.google.api-client:google-api-client-appengine:1.30.7
com.google.api-client:google-api-client-jackson2:1.27.0
com.google.api-client:google-api-client-java6:1.27.0
com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api-client:google-api-client-servlet:1.30.7
com.google.api-client:google-api-client:1.30.7
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
@@ -84,22 +84,22 @@ com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.8.2
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-appengine:1.34.0
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.30.1
com.google.http-client:google-http-client:1.34.0
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
com.google.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:metrics:1.0.7
com.google.monitoring-client:stackdriver:1.0.7
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-appengine:1.30.5
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.oauth-client:google-oauth-client-servlet:1.30.5
com.google.oauth-client:google-oauth-client:1.30.5
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -124,7 +124,7 @@ io.dropwizard.metrics:metrics-core:3.1.2
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-context:1.22.1
io.grpc:grpc-core:1.17.1
io.grpc:grpc-grpclb:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
@@ -146,10 +146,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.21.0
io.opencensus:opencensus-contrib-http-util:0.24.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -183,8 +183,8 @@ org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-lang3:3.5
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.apache.httpcomponents:httpclient:4.5.10
org.apache.httpcomponents:httpcore:4.4.12
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
@@ -193,6 +193,7 @@ org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.dom4j:dom4j:2.1.1
org.easymock:easymock:3.0
org.flywaydb:flyway-core:5.2.4
org.glassfish.jaxb:jaxb-runtime:2.3.1
org.glassfish.jaxb:txw2:2.3.1
org.hamcrest:hamcrest-core:1.3
+15 -14
View File
@@ -10,11 +10,11 @@ com.fasterxml.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
com.google.api-client:google-api-client-appengine:1.29.0
com.google.api-client:google-api-client-appengine:1.30.7
com.google.api-client:google-api-client-jackson2:1.27.0
com.google.api-client:google-api-client-java6:1.27.0
com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api-client:google-api-client-servlet:1.30.7
com.google.api-client:google-api-client:1.30.7
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
@@ -84,22 +84,22 @@ com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.8.2
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-appengine:1.34.0
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.30.1
com.google.http-client:google-http-client:1.34.0
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
com.google.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:metrics:1.0.7
com.google.monitoring-client:stackdriver:1.0.7
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-appengine:1.30.5
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.oauth-client:google-oauth-client-servlet:1.30.5
com.google.oauth-client:google-oauth-client:1.30.5
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -124,7 +124,7 @@ io.dropwizard.metrics:metrics-core:3.1.2
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-context:1.22.1
io.grpc:grpc-core:1.17.1
io.grpc:grpc-grpclb:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
@@ -146,10 +146,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.21.0
io.opencensus:opencensus-contrib-http-util:0.24.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -183,8 +183,8 @@ org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-lang3:3.5
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.apache.httpcomponents:httpclient:4.5.10
org.apache.httpcomponents:httpcore:4.4.12
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
@@ -193,6 +193,7 @@ org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.dom4j:dom4j:2.1.1
org.easymock:easymock:3.0
org.flywaydb:flyway-core:5.2.4
org.glassfish.jaxb:jaxb-runtime:2.3.1
org.glassfish.jaxb:txw2:2.3.1
org.hamcrest:hamcrest-core:1.3
@@ -18,11 +18,11 @@ com.github.jnr:jnr-ffi:2.1.9
com.github.jnr:jnr-posix:3.0.47
com.github.jnr:jnr-unixsocket:0.21
com.github.jnr:jnr-x86asm:1.0.2
com.google.api-client:google-api-client-appengine:1.29.0
com.google.api-client:google-api-client-appengine:1.30.7
com.google.api-client:google-api-client-jackson2:1.27.0
com.google.api-client:google-api-client-java6:1.27.0
com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api-client:google-api-client-servlet:1.30.7
com.google.api-client:google-api-client:1.30.7
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
@@ -95,22 +95,22 @@ com.google.guava:failureaccess:1.0.1
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.8.2
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-appengine:1.34.0
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.30.1
com.google.http-client:google-http-client:1.34.0
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
com.google.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:metrics:1.0.7
com.google.monitoring-client:stackdriver:1.0.7
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-appengine:1.30.5
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.oauth-client:google-oauth-client-servlet:1.30.5
com.google.oauth-client:google-oauth-client:1.30.5
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -135,7 +135,7 @@ io.dropwizard.metrics:metrics-core:3.1.2
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-context:1.22.1
io.grpc:grpc-core:1.17.1
io.grpc:grpc-grpclb:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
@@ -157,10 +157,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.21.0
io.opencensus:opencensus-contrib-http-util:0.24.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -193,8 +193,8 @@ org.apache.beam:beam-vendor-grpc-1_21_0:0.1
org.apache.beam:beam-vendor-guava-26_0-jre:0.1
org.apache.commons:commons-compress:1.19
org.apache.commons:commons-lang3:3.5
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.apache.httpcomponents:httpclient:4.5.10
org.apache.httpcomponents:httpcore:4.4.12
org.bouncycastle:bcpg-jdk15on:1.61
org.bouncycastle:bcprov-jdk15on:1.61
org.checkerframework:checker-qual:2.8.1
@@ -203,6 +203,7 @@ org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.dom4j:dom4j:2.1.1
org.easymock:easymock:3.0
org.flywaydb:flyway-core:5.2.4
org.glassfish.jaxb:jaxb-runtime:2.3.1
org.glassfish.jaxb:txw2:2.3.1
org.hibernate.common:hibernate-commons-annotations:5.1.0.Final
@@ -10,11 +10,11 @@ com.fasterxml.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
com.google.api-client:google-api-client-appengine:1.29.0
com.google.api-client:google-api-client-appengine:1.30.7
com.google.api-client:google-api-client-jackson2:1.27.0
com.google.api-client:google-api-client-java6:1.27.0
com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api-client:google-api-client-servlet:1.30.7
com.google.api-client:google-api-client:1.30.7
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
@@ -86,11 +86,11 @@ com.google.guava:guava-testlib:28.1-jre
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.8.2
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-appengine:1.34.0
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.30.1
com.google.http-client:google-http-client:1.34.0
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
@@ -98,11 +98,11 @@ com.google.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:contrib:1.0.7
com.google.monitoring-client:metrics:1.0.7
com.google.monitoring-client:stackdriver:1.0.7
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-appengine:1.30.5
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.oauth-client:google-oauth-client-servlet:1.30.5
com.google.oauth-client:google-oauth-client:1.30.5
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -133,7 +133,7 @@ io.github.classgraph:classgraph:4.8.52
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-context:1.22.1
io.grpc:grpc-core:1.17.1
io.grpc:grpc-grpclb:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
@@ -155,10 +155,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.21.0
io.opencensus:opencensus-contrib-http-util:0.24.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -198,8 +198,8 @@ org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.ftpserver:ftplet-api:1.0.6
org.apache.ftpserver:ftpserver-core:1.0.6
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.apache.httpcomponents:httpclient:4.5.10
org.apache.httpcomponents:httpcore:4.4.12
org.apache.mina:mina-core:2.0.4
org.apache.sshd:sshd-core:2.0.0
org.apache.sshd:sshd-scp:2.0.0
@@ -215,6 +215,7 @@ org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.dom4j:dom4j:2.1.1
org.easymock:easymock:3.0
org.flywaydb:flyway-core:5.2.4
org.glassfish.jaxb:jaxb-runtime:2.3.1
org.glassfish.jaxb:txw2:2.3.1
org.hamcrest:hamcrest-all:1.3
@@ -10,11 +10,11 @@ com.fasterxml.jackson.core:jackson-annotations:2.9.10
com.fasterxml.jackson.core:jackson-core:2.9.10
com.fasterxml.jackson.core:jackson-databind:2.9.10
com.fasterxml:classmate:1.3.4
com.google.api-client:google-api-client-appengine:1.29.0
com.google.api-client:google-api-client-appengine:1.30.7
com.google.api-client:google-api-client-jackson2:1.27.0
com.google.api-client:google-api-client-java6:1.27.0
com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api-client:google-api-client-servlet:1.30.7
com.google.api-client:google-api-client:1.30.7
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
@@ -85,11 +85,11 @@ com.google.guava:guava-testlib:28.1-jre
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.8.2
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-appengine:1.34.0
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.30.1
com.google.http-client:google-http-client:1.34.0
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
@@ -97,11 +97,11 @@ com.google.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:contrib:1.0.7
com.google.monitoring-client:metrics:1.0.7
com.google.monitoring-client:stackdriver:1.0.7
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-appengine:1.30.5
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.oauth-client:google-oauth-client-servlet:1.30.5
com.google.oauth-client:google-oauth-client:1.30.5
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -132,7 +132,7 @@ io.github.classgraph:classgraph:4.8.52
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-context:1.22.1
io.grpc:grpc-core:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
io.grpc:grpc-netty:1.17.1
@@ -153,10 +153,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.21.0
io.opencensus:opencensus-contrib-http-util:0.24.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -196,8 +196,8 @@ org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.ftpserver:ftplet-api:1.0.6
org.apache.ftpserver:ftpserver-core:1.0.6
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.apache.httpcomponents:httpclient:4.5.10
org.apache.httpcomponents:httpcore:4.4.12
org.apache.mina:mina-core:2.0.4
org.apache.sshd:sshd-core:2.0.0
org.apache.sshd:sshd-scp:2.0.0
@@ -213,6 +213,7 @@ org.codehaus.jackson:jackson-mapper-asl:1.9.13
org.codehaus.mojo:animal-sniffer-annotations:1.18
org.dom4j:dom4j:2.1.1
org.easymock:easymock:3.0
org.flywaydb:flyway-core:5.2.4
org.glassfish.jaxb:jaxb-runtime:2.3.1
org.glassfish.jaxb:txw2:2.3.1
org.hamcrest:hamcrest-all:1.3
@@ -18,11 +18,11 @@ com.github.jnr:jnr-ffi:2.1.9
com.github.jnr:jnr-posix:3.0.47
com.github.jnr:jnr-unixsocket:0.21
com.github.jnr:jnr-x86asm:1.0.2
com.google.api-client:google-api-client-appengine:1.29.0
com.google.api-client:google-api-client-appengine:1.30.7
com.google.api-client:google-api-client-jackson2:1.27.0
com.google.api-client:google-api-client-java6:1.27.0
com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api-client:google-api-client-servlet:1.30.7
com.google.api-client:google-api-client:1.30.7
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
@@ -97,11 +97,11 @@ com.google.guava:guava-testlib:28.1-jre
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.8.2
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-appengine:1.34.0
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.30.1
com.google.http-client:google-http-client:1.34.0
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
@@ -109,11 +109,11 @@ com.google.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:contrib:1.0.7
com.google.monitoring-client:metrics:1.0.7
com.google.monitoring-client:stackdriver:1.0.7
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-appengine:1.30.5
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.oauth-client:google-oauth-client-servlet:1.30.5
com.google.oauth-client:google-oauth-client:1.30.5
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -145,7 +145,7 @@ io.github.java-diff-utils:java-diff-utils:4.0
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-context:1.22.1
io.grpc:grpc-core:1.17.1
io.grpc:grpc-grpclb:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
@@ -167,10 +167,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.21.0
io.opencensus:opencensus-contrib-http-util:0.24.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -210,8 +210,8 @@ org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.ftpserver:ftplet-api:1.0.6
org.apache.ftpserver:ftpserver-core:1.0.6
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.apache.httpcomponents:httpclient:4.5.10
org.apache.httpcomponents:httpcore:4.4.12
org.apache.mina:mina-core:2.0.4
org.apache.sshd:sshd-core:2.0.0
org.apache.sshd:sshd-scp:2.0.0
@@ -18,11 +18,11 @@ com.github.jnr:jnr-ffi:2.1.9
com.github.jnr:jnr-posix:3.0.47
com.github.jnr:jnr-unixsocket:0.21
com.github.jnr:jnr-x86asm:1.0.2
com.google.api-client:google-api-client-appengine:1.29.0
com.google.api-client:google-api-client-appengine:1.30.7
com.google.api-client:google-api-client-jackson2:1.27.0
com.google.api-client:google-api-client-java6:1.27.0
com.google.api-client:google-api-client-servlet:1.29.0
com.google.api-client:google-api-client:1.29.2
com.google.api-client:google-api-client-servlet:1.30.7
com.google.api-client:google-api-client:1.30.7
com.google.api.grpc:grpc-google-cloud-bigquerystorage-v1beta1:0.44.0
com.google.api.grpc:grpc-google-cloud-bigtable-admin-v2:0.38.0
com.google.api.grpc:grpc-google-cloud-bigtable-v2:0.38.0
@@ -97,11 +97,11 @@ com.google.guava:guava-testlib:28.1-jre
com.google.guava:guava:28.1-jre
com.google.guava:listenablefuture:9999.0-empty-to-avoid-conflict-with-guava
com.google.gwt:gwt-user:2.8.2
com.google.http-client:google-http-client-appengine:1.29.2
com.google.http-client:google-http-client-jackson2:1.30.1
com.google.http-client:google-http-client-appengine:1.34.0
com.google.http-client:google-http-client-jackson2:1.32.1
com.google.http-client:google-http-client-jackson:1.20.0
com.google.http-client:google-http-client-protobuf:1.20.0
com.google.http-client:google-http-client:1.30.1
com.google.http-client:google-http-client:1.34.0
com.google.inject.extensions:guice-multibindings:4.1.0
com.google.inject:guice:4.1.0
com.google.j2objc:j2objc-annotations:1.3
@@ -109,11 +109,11 @@ com.google.jsinterop:jsinterop-annotations:1.0.2
com.google.monitoring-client:contrib:1.0.7
com.google.monitoring-client:metrics:1.0.7
com.google.monitoring-client:stackdriver:1.0.7
com.google.oauth-client:google-oauth-client-appengine:1.29.0
com.google.oauth-client:google-oauth-client-appengine:1.30.5
com.google.oauth-client:google-oauth-client-java6:1.28.0
com.google.oauth-client:google-oauth-client-jetty:1.28.0
com.google.oauth-client:google-oauth-client-servlet:1.29.0
com.google.oauth-client:google-oauth-client:1.29.2
com.google.oauth-client:google-oauth-client-servlet:1.30.5
com.google.oauth-client:google-oauth-client:1.30.5
com.google.protobuf.nano:protobuf-javanano:3.0.0-alpha-5
com.google.protobuf:protobuf-java-util:3.6.1
com.google.protobuf:protobuf-java:3.6.1
@@ -145,7 +145,7 @@ io.github.java-diff-utils:java-diff-utils:4.0
io.grpc:grpc-all:1.17.1
io.grpc:grpc-alts:1.17.1
io.grpc:grpc-auth:1.17.1
io.grpc:grpc-context:1.19.0
io.grpc:grpc-context:1.22.1
io.grpc:grpc-core:1.17.1
io.grpc:grpc-grpclb:1.17.1
io.grpc:grpc-netty-shaded:1.17.1
@@ -167,10 +167,10 @@ io.netty:netty-handler:4.1.30.Final
io.netty:netty-resolver:4.1.30.Final
io.netty:netty-tcnative-boringssl-static:2.0.17.Final
io.netty:netty-transport:4.1.30.Final
io.opencensus:opencensus-api:0.21.0
io.opencensus:opencensus-api:0.24.0
io.opencensus:opencensus-contrib-grpc-metrics:0.17.0
io.opencensus:opencensus-contrib-grpc-util:0.17.0
io.opencensus:opencensus-contrib-http-util:0.21.0
io.opencensus:opencensus-contrib-http-util:0.24.0
it.unimi.dsi:fastutil:6.5.16
javax.activation:activation:1.1
javax.activation:javax.activation-api:1.2.0
@@ -210,8 +210,8 @@ org.apache.commons:commons-lang3:3.8.1
org.apache.commons:commons-text:1.6
org.apache.ftpserver:ftplet-api:1.0.6
org.apache.ftpserver:ftpserver-core:1.0.6
org.apache.httpcomponents:httpclient:4.5.8
org.apache.httpcomponents:httpcore:4.4.11
org.apache.httpcomponents:httpclient:4.5.10
org.apache.httpcomponents:httpcore:4.4.12
org.apache.mina:mina-core:2.0.4
org.apache.sshd:sshd-core:2.0.0
org.apache.sshd:sshd-scp:2.0.0
@@ -61,6 +61,11 @@
<url-pattern>/registry-lock-get</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>frontend-servlet</servlet-name>
<url-pattern>/registry-lock-post</url-pattern>
</servlet-mapping>
<servlet-mapping>
<servlet-name>frontend-servlet</servlet-name>
<url-pattern>/registry-lock-verify</url-pattern>
@@ -53,7 +53,6 @@ import java.util.concurrent.ExecutionException;
import javax.persistence.Column;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import org.hibernate.annotations.Type;
import org.joda.time.DateTime;
import org.joda.time.Duration;
@@ -117,7 +116,6 @@ public abstract class EppResource extends BackupGroupRoot implements Buildable {
DateTime lastEppUpdateTime;
/** Status values associated with this resource. */
@Type(type = "google.registry.model.eppcommon.StatusValue$StatusValueSetType")
@Column(name = "statuses")
// TODO(mmuller): rename to "statuses" once we're off datastore.
Set<StatusValue> status;
@@ -162,7 +162,10 @@ public abstract class ImmutableObject implements Cloneable {
// values.
Map<String, Object> result = new LinkedHashMap<>();
for (Entry<Field, Object> entry : ModelUtils.getFieldValues(o).entrySet()) {
result.put(entry.getKey().getName(), toMapRecursive(entry.getValue()));
Field field = entry.getKey();
if (!field.isAnnotationPresent(IgnoredInDiffableMap.class)) {
result.put(field.getName(), toMapRecursive(entry.getValue()));
}
}
return result;
} else if (o instanceof Map) {
@@ -191,6 +194,12 @@ public abstract class ImmutableObject implements Cloneable {
}
}
/** Marker to indicate that this filed should be ignored by {@link #toDiffableFieldMap}. */
@Documented
@Retention(RUNTIME)
@Target(FIELD)
protected @interface IgnoredInDiffableMap {}
/** Returns a map of all object fields (including sensitive data) that's used to produce diffs. */
@SuppressWarnings("unchecked")
public Map<String, Object> toDiffableFieldMap() {
@@ -185,7 +185,6 @@ public class DomainBase extends EppResource
String idnTableName;
/** Fully qualified host names of this domain's active subordinate hosts. */
@org.hibernate.annotations.Type(type = "google.registry.persistence.StringSetUserType")
Set<String> subordinateHosts;
/** When this domain's registration will expire. */
@@ -16,20 +16,24 @@ package google.registry.model.eppcommon;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Strings.nullToEmpty;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static google.registry.util.CollectionUtils.nullToEmptyImmutableCopy;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.googlecode.objectify.annotation.AlsoLoad;
import com.googlecode.objectify.annotation.Ignore;
import com.googlecode.objectify.annotation.OnLoad;
import google.registry.model.Buildable;
import google.registry.model.ImmutableObject;
import google.registry.model.JsonMapBuilder;
import google.registry.model.Jsonifiable;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Stream;
import javax.persistence.Embeddable;
import javax.persistence.MappedSuperclass;
import javax.persistence.PostLoad;
import javax.persistence.Transient;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlTransient;
@@ -53,15 +57,17 @@ import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
public class Address extends ImmutableObject implements Jsonifiable {
/** The schema validation will enforce that this has 3 lines at most. */
// TODO(shicong): Remove this field after migration. We need to figure out how to generate same
// XML from streetLine[1,2,3].
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)
@Transient
List<String> street;
@Ignore String streetLine1;
@Ignore @XmlTransient @IgnoredInDiffableMap String streetLine1;
@Ignore String streetLine2;
@Ignore @XmlTransient @IgnoredInDiffableMap String streetLine2;
@Ignore String streetLine3;
@Ignore @XmlTransient @IgnoredInDiffableMap String streetLine3;
@XmlJavaTypeAdapter(NormalizedStringAdapter.class)
String city;
@@ -86,18 +92,6 @@ public class Address extends ImmutableObject implements Jsonifiable {
}
}
public String getStreetLine1() {
return streetLine1;
}
public String getStreetLine2() {
return streetLine2;
}
public String getStreetLine13() {
return streetLine3;
}
public String getCity() {
return city;
}
@@ -144,6 +138,9 @@ public class Address extends ImmutableObject implements Jsonifiable {
street == null || (!street.isEmpty() && street.size() <= 3),
"Street address must have [1-3] lines: %s", street);
getInstance().street = street;
getInstance().streetLine1 = street.get(0);
getInstance().streetLine2 = street.size() >= 2 ? street.get(1) : null;
getInstance().streetLine3 = street.size() == 3 ? street.get(2) : null;
return this;
}
@@ -171,8 +168,14 @@ public class Address extends ImmutableObject implements Jsonifiable {
}
}
@OnLoad
void setStreetForCloudSql() {
/**
* Sets {@link #streetLine1}, {@link #streetLine2} and {@link #streetLine3} after loading the
* entity from Datastore.
*
* <p>This callback method is used by Objectify to set streetLine[1,2,3] fields as they are not
* persisted in the Datastore. TODO(shicong): Delete this method after database migration.
*/
void onLoad(@AlsoLoad("street") List<String> street) {
if (street == null || street.size() == 0) {
return;
}
@@ -180,4 +183,22 @@ public class Address extends ImmutableObject implements Jsonifiable {
streetLine2 = street.size() >= 2 ? street.get(1) : null;
streetLine3 = street.size() >= 3 ? street.get(2) : null;
}
/**
* Sets {@link #street} after loading the entity from Cloud SQL.
*
* <p>This callback method is used by Hibernate to set {@link #street} field as it is not
* persisted in Cloud SQL. We are doing this because the street list field is exposed by Address
* class and is used everywhere in our code base. Also, setting/reading a list of strings is more
* convenient.
*/
@PostLoad
void postLoad() {
street =
streetLine1 == null
? null
: Stream.of(streetLine1, streetLine2, streetLine3)
.filter(Objects::nonNull)
.collect(toImmutableList());
}
}
@@ -25,7 +25,6 @@ import google.registry.model.domain.DomainBase;
import google.registry.model.host.HostResource;
import google.registry.model.translators.EnumToAttributeAdapter.EppEnum;
import google.registry.model.translators.StatusValueAdapter;
import google.registry.persistence.EnumSetUserType;
import javax.xml.bind.annotation.adapters.XmlJavaTypeAdapter;
/**
@@ -166,11 +165,4 @@ public enum StatusValue implements EppEnum {
return StatusValue.valueOf(LOWER_CAMEL.to(UPPER_UNDERSCORE, nullToEmpty(xmlName)));
}
/** Hibernate type for sets of {@link StatusValue}. */
public static class StatusValueSetType extends EnumSetUserType<StatusValue> {
@Override
protected StatusValue convertToElem(String value) {
return StatusValue.valueOf(value);
}
}
}
@@ -89,9 +89,10 @@ import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Embedded;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Table;
import javax.persistence.Transient;
import org.hibernate.annotations.Type;
import org.joda.money.CurrencyUnit;
import org.joda.time.DateTime;
@@ -253,21 +254,20 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
/** The type of this registrar. */
@Column(nullable = false)
@Enumerated(EnumType.STRING)
Type type;
/** The state of this registrar. */
@Enumerated(EnumType.STRING)
State state;
/** The set of TLDs which this registrar is allowed to access. */
// TODO(b/147908600): Investigate how to automatically apply user type
@org.hibernate.annotations.Type(type = "google.registry.persistence.StringSetUserType")
Set<String> allowedTlds;
/** Host name of WHOIS server. */
String whoisServer;
/** Base URLs for the registrar's RDAP servers. */
@org.hibernate.annotations.Type(type = "google.registry.persistence.StringSetUserType")
Set<String> rdapBaseUrls;
/**
@@ -295,7 +295,6 @@ public class Registrar extends ImmutableObject implements Buildable, Jsonifiable
String failoverClientCertificateHash;
/** A whitelist of netmasks (in CIDR notation) which the client is allowed to connect from. */
@org.hibernate.annotations.Type(type = "google.registry.persistence.CidrAddressBlockListUserType")
List<CidrAddressBlock> ipAddressWhitelist;
/** A hashed password for EPP access. The hash is a base64 encoded SHA256 string. */
@@ -45,6 +45,9 @@ import google.registry.model.annotations.ReportedOn;
import java.util.Arrays;
import java.util.Map;
import java.util.Set;
import javax.persistence.Column;
import javax.persistence.Table;
import javax.persistence.Transient;
/**
* A contact for a Registrar. Note, equality, hashCode and comparable have been overridden to only
@@ -56,10 +59,16 @@ import java.util.Set;
*/
@ReportedOn
@Entity
@javax.persistence.Entity
@Table(
name = "RegistrarPoc",
indexes = {
@javax.persistence.Index(columnList = "gaeUserId", name = "registrarpoc_gae_user_id_idx")
})
// TODO(shicong): Rename the class name to RegistrarPoc after database migration
public class RegistrarContact extends ImmutableObject implements Jsonifiable {
@Parent
Key<Registrar> parent;
@Parent @Transient Key<Registrar> parent;
/**
* Registrar contacts types for partner communication tracking.
@@ -99,6 +108,8 @@ public class RegistrarContact extends ImmutableObject implements Jsonifiable {
/** The email address of the contact. */
@Id
@javax.persistence.Id
@Column(nullable = false)
String emailAddress;
/** The voice number of the contact. */
@@ -108,8 +119,8 @@ public class RegistrarContact extends ImmutableObject implements Jsonifiable {
String faxNumber;
/**
* Multiple types are used to associate the registrar contact with
* various mailing groups. This data is internal to the registry.
* Multiple types are used to associate the registrar contact with various mailing groups. This
* data is internal to the registry.
*/
Set<Type> types;
@@ -31,6 +31,7 @@ import google.registry.ui.server.registrar.OteStatusAction;
import google.registry.ui.server.registrar.RegistrarConsoleModule;
import google.registry.ui.server.registrar.RegistrarSettingsAction;
import google.registry.ui.server.registrar.RegistryLockGetAction;
import google.registry.ui.server.registrar.RegistryLockPostAction;
import google.registry.ui.server.registrar.RegistryLockVerifyAction;
/** Dagger component with per-request lifetime for "default" App Engine module. */
@@ -54,6 +55,8 @@ interface FrontendRequestComponent {
RegistryLockGetAction registryLockGetAction();
RegistryLockPostAction registryLockPostAction();
RegistryLockVerifyAction registryLockVerifyAction();
@Subcomponent.Builder
@@ -16,20 +16,24 @@ package google.registry.persistence;
import google.registry.util.CidrAddressBlock;
import java.util.List;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/**
* Hibernate {@link org.hibernate.usertype.UserType} for storing/retrieving {@link
* List<CidrAddressBlock>} objects.
* JPA {@link AttributeConverter} for storing/retrieving {@link List<CidrAddressBlock>} objects.
* TODO(shicong): Investigate if we can have one converter for any List type
*/
public class CidrAddressBlockListUserType extends StringListUserType<CidrAddressBlock> {
@Converter(autoApply = true)
public class CidrAddressBlockListConverter extends StringListConverterBase<CidrAddressBlock> {
@Override
protected CidrAddressBlock convertToElem(String columnValue) {
return columnValue == null ? null : CidrAddressBlock.create(columnValue);
String toString(CidrAddressBlock element) {
return element.toString();
}
@Override
protected String convertToColumn(CidrAddressBlock elementValue) {
return elementValue == null ? null : elementValue.toString();
CidrAddressBlock fromString(String value) {
return CidrAddressBlock.create(value);
}
}
@@ -29,20 +29,26 @@ public class CurrencyToBillingMapUserType extends MapUserType {
@Override
public Object toEntityTypeMap(Map<String, String> map) {
return map.entrySet().stream()
.collect(
toImmutableMap(
entry -> CurrencyUnit.of(entry.getKey()),
entry ->
new BillingAccountEntry(CurrencyUnit.of(entry.getKey()), entry.getValue())));
return map == null
? null
: map.entrySet().stream()
.collect(
toImmutableMap(
entry -> CurrencyUnit.of(entry.getKey()),
entry ->
new BillingAccountEntry(
CurrencyUnit.of(entry.getKey()), entry.getValue())));
}
@Override
public Map<String, String> toDbSupportedMap(Object map) {
return ((Map<CurrencyUnit, BillingAccountEntry>) map)
.entrySet().stream()
.collect(
toImmutableMap(
entry -> entry.getKey().getCode(), entry -> entry.getValue().getAccountId()));
return map == null
? null
: ((Map<CurrencyUnit, BillingAccountEntry>) map)
.entrySet().stream()
.collect(
toImmutableMap(
entry -> entry.getKey().getCode(),
entry -> entry.getValue().getAccountId()));
}
}
@@ -1,119 +0,0 @@
// Copyright 2020 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.persistence;
import google.registry.util.TypeUtils.TypeInstantiator;
import java.sql.Array;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Collection;
import org.hibernate.HibernateException;
import org.hibernate.engine.spi.SharedSessionContractImplementor;
/**
* Generic Hibernate user type to store/retrieve Java collection as an array in Cloud SQL.
*
* @param <T> the concrete {@link Collection} type of the entity field
* @param <E> the Java type of the element for the collection of the entity field
* @param <C> the JDBC supported type of the element in the DB column array
*/
public abstract class GenericCollectionUserType<T extends Collection<E>, E, C>
extends MutableUserType {
abstract T getNewCollection();
abstract ArrayColumnType getColumnType();
enum ArrayColumnType {
STRING(Types.ARRAY, "text");
final int typeCode;
final String typeName;
ArrayColumnType(int typeCode, String typeName) {
this.typeCode = typeCode;
this.typeName = typeName;
}
int getTypeCode() {
return typeCode;
}
String getTypeName() {
return typeName;
}
String getTypeDdlName() {
return typeName + "[]";
}
}
@Override
public Class returnedClass() {
return new TypeInstantiator<T>(getClass()) {}.getExactType();
}
@Override
public int[] sqlTypes() {
return new int[] {getColumnType().getTypeCode()};
}
@Override
public Object nullSafeGet(
ResultSet rs, String[] names, SharedSessionContractImplementor session, Object owner)
throws HibernateException, SQLException {
if (rs.getArray(names[0]) != null) {
T result = getNewCollection();
for (C element : (C[]) rs.getArray(names[0]).getArray()) {
result.add(convertToElem(element));
}
return result;
}
return null;
}
@Override
public void nullSafeSet(
PreparedStatement st, Object value, int index, SharedSessionContractImplementor session)
throws HibernateException, SQLException {
if (value == null) {
st.setArray(index, null);
return;
}
T collection = (T) value;
Array arr =
st.getConnection()
.createArrayOf(
getColumnType().getTypeName(),
collection.stream().map(this::convertToColumn).toArray());
st.setArray(index, arr);
}
/**
* Override this to convert an element value retrieved from the database to a different type.
*
* <p>This method is useful when encoding a java type to one of the types that can be used as an
* array element.
*/
protected E convertToElem(C columnValue) {
return (E) columnValue;
}
protected C convertToColumn(E elementValue) {
return (C) elementValue;
}
}
@@ -1,34 +0,0 @@
// Copyright 2020 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.persistence;
import google.registry.util.TypeUtils.TypeInstantiator;
import javax.persistence.AttributeConverter;
/** Generic converter for storing/retrieving {@link Enum} objects. */
public class GenericEnumConverter<T extends Enum<T>> implements AttributeConverter<T, String> {
@Override
public String convertToDatabaseColumn(T attribute) {
return attribute == null ? null : attribute.toString();
}
@Override
public T convertToEntityAttribute(String dbData) {
return dbData == null
? null
: Enum.valueOf(new TypeInstantiator<T>(getClass()) {}.getExactType(), dbData);
}
}
@@ -13,9 +13,10 @@
// limitations under the License.
package google.registry.persistence;
import google.registry.persistence.GenericCollectionUserType.ArrayColumnType;
import java.sql.Types;
import org.hibernate.boot.model.TypeContributions;
import org.hibernate.dialect.PostgreSQL95Dialect;
import org.hibernate.service.ServiceRegistry;
/** Nomulus mapping rules for column types in Postgresql. */
public class NomulusPostgreSQLDialect extends PostgreSQL95Dialect {
@@ -25,8 +26,15 @@ public class NomulusPostgreSQLDialect extends PostgreSQL95Dialect {
registerColumnType(Types.TIMESTAMP_WITH_TIMEZONE, "timestamptz");
registerColumnType(Types.TIMESTAMP, "timestamptz");
registerColumnType(Types.OTHER, "hstore");
for (ArrayColumnType arrayType : ArrayColumnType.values()) {
registerColumnType(arrayType.getTypeCode(), arrayType.getTypeDdlName());
}
registerColumnType(
StringCollectionDescriptor.COLUMN_TYPE, StringCollectionDescriptor.COLUMN_DDL_NAME);
}
@Override
public void contributeTypes(
TypeContributions typeContributions, ServiceRegistry serviceRegistry) {
super.contributeTypes(typeContributions, serviceRegistry);
typeContributions.contributeJavaTypeDescriptor(new StringCollectionDescriptor());
typeContributions.contributeSqlTypeDescriptor(new StringCollectionDescriptor());
}
}
@@ -14,25 +14,21 @@
package google.registry.persistence;
import java.util.HashSet;
import google.registry.model.registrar.RegistrarContact.Type;
import java.util.Set;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/** Abstract Hibernate user type for storing/retrieving {@link Set<Enum<E>>}. */
public class EnumSetUserType<E extends Enum<E>>
extends GenericCollectionUserType<Set<E>, E, String> {
/** JPA {@link AttributeConverter} for storing/retrieving {@link Set<Type>}. */
@Converter(autoApply = true)
public class RegistrarPocSetConverter extends StringSetConverterBase<Type> {
@Override
Set<E> getNewCollection() {
return new HashSet<>();
String toString(Type element) {
return element.name();
}
@Override
ArrayColumnType getColumnType() {
return ArrayColumnType.STRING;
}
@Override
public Class returnedClass() {
return Set.class;
Type fromString(String value) {
return Type.valueOf(value);
}
}
@@ -14,19 +14,22 @@
package google.registry.persistence;
import com.google.common.collect.Sets;
import google.registry.model.eppcommon.StatusValue;
import java.util.Set;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/** Abstract Hibernate user type for storing/retrieving {@link Set<String>}. */
public class StringSetUserType<E> extends GenericCollectionUserType<Set<E>, E, String> {
/** JPA {@link AttributeConverter} for storing/retrieving {@link Set<StatusValue>}. */
@Converter(autoApply = true)
public class StatusValueSetConverter extends StringSetConverterBase<StatusValue> {
@Override
Set<E> getNewCollection() {
return Sets.newHashSet();
String toString(StatusValue element) {
return element.name();
}
@Override
ArrayColumnType getColumnType() {
return ArrayColumnType.STRING;
StatusValue fromString(String value) {
return StatusValue.valueOf(value);
}
}
@@ -0,0 +1,187 @@
// Copyright 2020 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.persistence;
import static google.registry.persistence.StringCollectionDescriptor.StringCollection;
import com.google.common.collect.ImmutableList;
import java.sql.Array;
import java.sql.CallableStatement;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Types;
import java.util.Collection;
import org.hibernate.type.descriptor.ValueBinder;
import org.hibernate.type.descriptor.ValueExtractor;
import org.hibernate.type.descriptor.WrapperOptions;
import org.hibernate.type.descriptor.java.AbstractTypeDescriptor;
import org.hibernate.type.descriptor.java.JavaTypeDescriptor;
import org.hibernate.type.descriptor.spi.JdbcRecommendedSqlTypeMappingContext;
import org.hibernate.type.descriptor.sql.BasicBinder;
import org.hibernate.type.descriptor.sql.BasicExtractor;
import org.hibernate.type.descriptor.sql.SqlTypeDescriptor;
/**
* The {@link JavaTypeDescriptor} and {@link SqlTypeDescriptor} for {@link StringCollection}.
*
* <p>A {@link StringCollection} object is a simple wrapper for a {@link Collection<String>} which
* can be stored as a string array in the database. The {@link JavaTypeDescriptor} and {@link
* SqlTypeDescriptor} is used by JPA/Hibernate to map between the collection and {@link Array} which
* is the actual type that JDBC uses to read from and write to the database.
*
* @see <a
* href="https://docs.jboss.org/hibernate/orm/current/userguide/html_single/Hibernate_User_Guide.html#basic-jpa-convert">JPA
* 2.1 AttributeConverters</a>
*/
public class StringCollectionDescriptor extends AbstractTypeDescriptor<StringCollection>
implements SqlTypeDescriptor {
public static final int COLUMN_TYPE = Types.ARRAY;
public static final String COLUMN_NAME = "text";
public static final String COLUMN_DDL_NAME = COLUMN_NAME + "[]";
protected StringCollectionDescriptor() {
super(StringCollection.class);
}
@Override
public StringCollection fromString(String string) {
throw new UnsupportedOperationException(
"Constructing StringCollectionDescriptor from string is not allowed");
}
@Override
public <X> X unwrap(StringCollection value, Class<X> type, WrapperOptions options) {
if (value == null) {
return null;
}
if (Collection.class.isAssignableFrom(type)) {
return (X) value.getCollection();
}
throw unknownUnwrap(type);
}
@Override
public <X> StringCollection wrap(X value, WrapperOptions options) {
if (value == null) {
return null;
}
if (value instanceof Array) {
try {
String[] arr = (String[]) ((Array) value).getArray();
ImmutableList.Builder<String> builder = new ImmutableList.Builder<>();
for (String str : arr) {
builder.add(str);
}
return StringCollection.create(builder.build());
} catch (SQLException e) {
throw new RuntimeException(e);
}
}
throw unknownWrap(value.getClass());
}
@Override
public SqlTypeDescriptor getJdbcRecommendedSqlType(JdbcRecommendedSqlTypeMappingContext context) {
return this;
}
@Override
public int getSqlType() {
return COLUMN_TYPE;
}
@Override
public boolean canBeRemapped() {
return false;
}
@Override
public <X> ValueBinder<X> getBinder(JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicBinder<X>(javaTypeDescriptor, this) {
@Override
protected void doBind(PreparedStatement st, X value, int index, WrapperOptions options)
throws SQLException {
if (value == null) {
st.setArray(index, null);
return;
}
if (value instanceof StringCollection) {
StringCollection stringCollection = (StringCollection) value;
if (stringCollection.getCollection() == null) {
st.setArray(index, null);
} else {
st.setArray(
index,
st.getConnection()
.createArrayOf(COLUMN_NAME, stringCollection.getCollection().toArray()));
}
} else {
throw new UnsupportedOperationException(
String.format(
"Binding type %s is not supported by StringCollectionDescriptor",
value.getClass().getName()));
}
}
@Override
protected void doBind(CallableStatement st, X value, String name, WrapperOptions options)
throws SQLException {
// CallableStatement.setArray() doesn't have an overload version for setting array by its
// column name
throw new UnsupportedOperationException(
"Binding array by its column name is not supported");
}
};
}
@Override
public <X> ValueExtractor<X> getExtractor(JavaTypeDescriptor<X> javaTypeDescriptor) {
return new BasicExtractor<X>(javaTypeDescriptor, this) {
@Override
protected X doExtract(ResultSet rs, String name, WrapperOptions options) throws SQLException {
return javaTypeDescriptor.wrap(rs.getArray(name), options);
}
@Override
protected X doExtract(CallableStatement statement, int index, WrapperOptions options)
throws SQLException {
return javaTypeDescriptor.wrap(statement.getArray(index), options);
}
@Override
protected X doExtract(CallableStatement statement, String name, WrapperOptions options)
throws SQLException {
return javaTypeDescriptor.wrap(statement.getArray(name), options);
}
};
}
public static class StringCollection {
private Collection<String> collection;
private StringCollection(Collection<String> collection) {
this.collection = collection;
}
public static StringCollection create(Collection<String> collection) {
return new StringCollection(collection);
}
public Collection<String> getCollection() {
return collection;
}
}
}
@@ -14,9 +14,21 @@
package google.registry.persistence;
import google.registry.model.registrar.Registrar;
import java.util.List;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/** JPA converter for storing/retrieving {@link Registrar.State} objects. */
/** JPA {@link AttributeConverter} for storing/retrieving {@link List<String>}. */
@Converter(autoApply = true)
public class RegistrarStateConverter extends GenericEnumConverter<Registrar.State> {}
public class StringListConverter extends StringListConverterBase<String> {
@Override
String toString(String element) {
return element;
}
@Override
String fromString(String value) {
return value;
}
}
@@ -0,0 +1,48 @@
// Copyright 2020 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.persistence;
import static com.google.common.collect.ImmutableList.toImmutableList;
import google.registry.persistence.StringCollectionDescriptor.StringCollection;
import java.util.List;
import javax.persistence.AttributeConverter;
/**
* Base JPA converter for {@link List} objects that are stored as an array of strings in the
* database.
*/
public abstract class StringListConverterBase<T>
implements AttributeConverter<List<T>, StringCollection> {
abstract String toString(T element);
abstract T fromString(String value);
@Override
public StringCollection convertToDatabaseColumn(List<T> attribute) {
return attribute == null
? null
: StringCollection.create(
attribute.stream().map(this::toString).collect(toImmutableList()));
}
@Override
public List<T> convertToEntityAttribute(StringCollection dbData) {
return dbData == null || dbData.getCollection() == null
? null
: dbData.getCollection().stream().map(this::fromString).collect(toImmutableList());
}
}
@@ -1,32 +0,0 @@
// Copyright 2020 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.persistence;
import com.google.common.collect.Lists;
import java.util.List;
/** Abstract Hibernate user type for storing/retrieving {@link List<String>}. */
public class StringListUserType<E> extends GenericCollectionUserType<List<E>, E, String> {
@Override
List<E> getNewCollection() {
return Lists.newArrayList();
}
@Override
ArrayColumnType getColumnType() {
return ArrayColumnType.STRING;
}
}
@@ -14,9 +14,21 @@
package google.registry.persistence;
import google.registry.model.registrar.Registrar;
import java.util.Set;
import javax.persistence.AttributeConverter;
import javax.persistence.Converter;
/** JPA converter for storing/retrieving {@link Registrar.Type} objects. */
/** JPA {@link AttributeConverter} for storing/retrieving {@link Set<String>}. */
@Converter(autoApply = true)
public class RegistrarTypeConverter extends GenericEnumConverter<Registrar.Type> {}
public class StringSetConverter extends StringSetConverterBase<String> {
@Override
String toString(String element) {
return element;
}
@Override
String fromString(String value) {
return value;
}
}
@@ -0,0 +1,47 @@
// Copyright 2020 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.persistence;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import google.registry.persistence.StringCollectionDescriptor.StringCollection;
import java.util.Set;
import javax.persistence.AttributeConverter;
/**
* Base JPA converter for {@link Set} objects that are stored as an array of strings in the
* database.
*/
public abstract class StringSetConverterBase<T>
implements AttributeConverter<Set<T>, StringCollection> {
abstract String toString(T element);
abstract T fromString(String value);
@Override
public StringCollection convertToDatabaseColumn(Set<T> attribute) {
return attribute == null
? null
: StringCollection.create(attribute.stream().map(this::toString).collect(toImmutableSet()));
}
@Override
public Set<T> convertToEntityAttribute(StringCollection dbData) {
return dbData == null || dbData.getCollection() == null
? null
: dbData.getCollection().stream().map(this::fromString).collect(toImmutableSet());
}
}
@@ -0,0 +1,73 @@
// Copyright 2020 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.schema.registrar;
import static com.google.common.base.Preconditions.checkArgument;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import google.registry.model.registrar.Registrar;
import java.util.Optional;
/** Data access object for {@link Registrar}. */
public class RegistrarDao {
private RegistrarDao() {}
/** Persists a new or updates an existing registrar in Cloud SQL. */
public static void saveNew(Registrar registrar) {
checkArgumentNotNull(registrar, "registrar must be specified");
jpaTm().transact(() -> jpaTm().getEntityManager().persist(registrar));
}
/** Updates an existing registrar in Cloud SQL, throws excpetion if it does not exist. */
public static void update(Registrar registrar) {
checkArgumentNotNull(registrar, "registrar must be specified");
jpaTm()
.transact(
() -> {
checkArgument(
checkExists(registrar.getClientId()),
"A registrar of this id does not exist: %s.",
registrar.getClientId());
jpaTm().getEntityManager().merge(registrar);
});
}
/** Returns whether the registrar of the given id exists. */
public static boolean checkExists(String clientId) {
checkArgumentNotNull(clientId, "clientId must be specified");
return jpaTm()
.transact(
() ->
jpaTm()
.getEntityManager()
.createQuery(
"SELECT 1 FROM Registrar WHERE clientIdentifier = :clientIdentifier",
Integer.class)
.setParameter("clientIdentifier", clientId)
.setMaxResults(1)
.getResultList()
.size()
> 0);
}
/** Loads the registrar by its id, returns empty if it doesn't exist. */
public static Optional<Registrar> load(String clientId) {
checkArgumentNotNull(clientId, "clientId must be specified");
return Optional.ofNullable(
jpaTm().transact(() -> jpaTm().getEntityManager().find(Registrar.class, clientId)));
}
}
@@ -0,0 +1,132 @@
// Copyright 2020 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.schema.server;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import google.registry.model.ImmutableObject;
import google.registry.schema.server.Lock.LockId;
import google.registry.util.DateTimeUtils;
import java.io.Serializable;
import java.time.ZonedDateTime;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.IdClass;
import javax.persistence.Table;
import org.joda.time.DateTime;
import org.joda.time.Duration;
/**
* A lock on some shared resource.
*
* <p>Locks are either specific to a tld or global to the entire system, in which case a tld of
* {@link GLOBAL} is used.
*
* <p>This uses a compound primary key as defined in {@link LockId}.
*/
@Entity
@Table
@IdClass(LockId.class)
public class Lock {
/** The resource name used to create the lock. */
@Column(nullable = false)
@Id
String resourceName;
/** The tld used to create the lock. */
@Column(nullable = false)
@Id
String tld;
/**
* Unique log ID of the request that owns this lock.
*
* <p>When that request is no longer running (is finished), the lock can be considered implicitly
* released.
*
* <p>See {@link RequestStatusCheckerImpl#getLogId} for details about how it's created in
* practice.
*/
@Column(nullable = false)
String requestLogId;
/** When the lock was acquired. Used for logging. */
@Column(nullable = false)
ZonedDateTime acquiredTime;
/** When the lock can be considered implicitly released. */
@Column(nullable = false)
ZonedDateTime expirationTime;
/** The scope of a lock that is not specific to a single tld. */
static final String GLOBAL = "GLOBAL";
/**
* Validate input and create a new {@link Lock} for the given resource name in the specified tld.
*/
private Lock(
String resourceName,
String tld,
String requestLogId,
DateTime acquiredTime,
Duration leaseLength) {
this.resourceName = checkArgumentNotNull(resourceName, "The resource name cannot be null");
this.tld = checkArgumentNotNull(tld, "The tld cannot be null. For a global lock, use GLOBAL");
this.requestLogId =
checkArgumentNotNull(requestLogId, "The requestLogId of the lock cannot be null");
this.acquiredTime =
DateTimeUtils.toZonedDateTime(
checkArgumentNotNull(acquiredTime, "The acquired time of the lock cannot be null"));
checkArgumentNotNull(leaseLength, "The lease length of the lock cannot be null");
this.expirationTime = DateTimeUtils.toZonedDateTime(acquiredTime.plus(leaseLength));
}
// Hibernate requires a default constructor.
private Lock() {}
/** Constructs a {@link Lock} object. */
public static Lock create(
String resourceName,
String tld,
String requestLogId,
DateTime acquiredTime,
Duration leaseLength) {
checkArgumentNotNull(
tld, "The tld cannot be null. To create a global lock, use the createGlobal method");
return new Lock(resourceName, tld, requestLogId, acquiredTime, leaseLength);
}
/** Constructs a {@link Lock} object with a {@link GLOBAL} scope. */
public static Lock createGlobal(
String resourceName, String requestLogId, DateTime acquiredTime, Duration leaseLength) {
return new Lock(resourceName, GLOBAL, requestLogId, acquiredTime, leaseLength);
}
static class LockId extends ImmutableObject implements Serializable {
String resourceName;
String tld;
private LockId() {}
LockId(String resourceName, String tld) {
this.resourceName = checkArgumentNotNull(resourceName, "The resource name cannot be null");
this.tld = tld;
}
}
}
@@ -0,0 +1,76 @@
// Copyright 2020 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.schema.server;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.schema.server.Lock.GLOBAL;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import google.registry.schema.server.Lock.LockId;
import java.util.Optional;
/** Data access object class for {@link Lock}. */
public class LockDao {
/** Saves the {@link Lock} object to Cloud SQL. */
public static void saveNew(Lock lock) {
jpaTm()
.transact(
() -> {
jpaTm().getEntityManager().persist(lock);
});
}
/**
* Loads and returns a {@link Lock} object with the given resourceName and tld from Cloud SQL if
* it exists, else empty.
*/
public static Optional<Lock> load(String resourceName, String tld) {
checkArgumentNotNull(resourceName, "The resource name of the lock to load cannot be null");
checkArgumentNotNull(tld, "The tld of the lock to load cannot be null");
return Optional.ofNullable(
jpaTm()
.transact(
() -> jpaTm().getEntityManager().find(Lock.class, new LockId(resourceName, tld))));
}
/**
* Loads a global {@link Lock} object with the given resourceName from Cloud SQL if it exists,
* else empty.
*/
public static Optional<Lock> load(String resourceName) {
checkArgumentNotNull(resourceName, "The resource name of the lock to load cannot be null");
return Optional.ofNullable(
jpaTm()
.transact(
() ->
jpaTm().getEntityManager().find(Lock.class, new LockId(resourceName, GLOBAL))));
}
/**
* Deletes the given {@link Lock} object from Cloud SQL. This method is idempotent and will simply
* return if the lock has already been deleted.
*/
public static void delete(Lock lock) {
jpaTm()
.transact(
() -> {
Optional<Lock> loadedLock = load(lock.resourceName, lock.tld);
if (loadedLock.isPresent()) {
jpaTm().getEntityManager().remove(loadedLock.get());
}
});
}
}
@@ -18,6 +18,7 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Predicates.isNull;
import static com.google.common.base.Strings.isNullOrEmpty;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.util.DomainNameUtils.canonicalizeDomainName;
import static google.registry.util.RegistrarUtils.normalizeRegistrarName;
import static java.nio.charset.StandardCharsets.US_ASCII;
@@ -28,6 +29,7 @@ import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.common.flogger.FluentLogger;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registry.Registry;
@@ -53,6 +55,8 @@ import org.joda.time.DateTime;
/** Shared base class for commands to create or update a {@link Registrar}. */
abstract class CreateOrUpdateRegistrarCommand extends MutatingCommand {
static final FluentLogger logger = FluentLogger.forEnclosingClass();
@Parameter(
description = "Client identifier of the registrar account",
required = true)
@@ -458,4 +462,26 @@ abstract class CreateOrUpdateRegistrarCommand extends MutatingCommand {
stageEntityChange(oldRegistrar, newRegistrar);
}
}
@Override
protected String execute() throws Exception {
// Save registrar to Datastore and output its response
logger.atInfo().log(super.execute());
String cloudSqlMessage;
try {
jpaTm()
.transact(
() ->
getChangedEntities().forEach(newEntity -> saveToCloudSql((Registrar) newEntity)));
cloudSqlMessage =
String.format("Updated %d entities in Cloud SQL.\n", getChangedEntities().size());
} catch (Throwable t) {
cloudSqlMessage = "Unexpected error saving registrar to Cloud SQL from nomulus tool command";
logger.atSevere().withCause(t).log(cloudSqlMessage);
}
return cloudSqlMessage;
}
abstract void saveToCloudSql(Registrar registrar);
}
@@ -62,12 +62,6 @@ public abstract class CreateOrUpdateReservedListCommand extends MutatingCommand
arity = 1)
Boolean shouldPublish;
@Parameter(
names = {"--also_cloud_sql"},
description =
"Persist reserved list to Cloud SQL in addition to Datastore; defaults to false.")
boolean alsoCloudSql;
google.registry.schema.tld.ReservedList cloudSqlReservedList;
abstract void saveToCloudSql();
@@ -78,23 +72,18 @@ public abstract class CreateOrUpdateReservedListCommand extends MutatingCommand
String output = super.execute();
logger.atInfo().log(output);
String cloudSqlMessage;
if (alsoCloudSql) {
String cloudSqlMessage =
String.format(
"Saved reserved list %s with %d entries",
name, cloudSqlReservedList.getLabelsToReservations().size());
try {
logger.atInfo().log("Saving reserved list to Cloud SQL for TLD %s", name);
saveToCloudSql();
logger.atInfo().log(cloudSqlMessage);
} catch (Throwable e) {
cloudSqlMessage =
String.format(
"Saved reserved list %s with %d entries",
name, cloudSqlReservedList.getLabelsToReservations().size());
try {
logger.atInfo().log("Saving reserved list to Cloud SQL for TLD %s", name);
saveToCloudSql();
logger.atInfo().log(cloudSqlMessage);
} catch (Throwable e) {
cloudSqlMessage =
"Unexpected error saving reserved list to Cloud SQL from nomulus tool command";
logger.atSevere().withCause(e).log(cloudSqlMessage);
}
} else {
cloudSqlMessage = "Persisting reserved list to Cloud SQL is not enabled";
"Unexpected error saving reserved list to Cloud SQL from nomulus tool command";
logger.atSevere().withCause(e).log(cloudSqlMessage);
}
return cloudSqlMessage;
}
@@ -32,6 +32,7 @@ import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Streams;
import google.registry.config.RegistryEnvironment;
import google.registry.model.registrar.Registrar;
import google.registry.schema.registrar.RegistrarDao;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
@@ -69,6 +70,11 @@ final class CreateRegistrarCommand extends CreateOrUpdateRegistrarCommand
registrarState = Optional.ofNullable(registrarState).orElse(ACTIVE);
}
@Override
void saveToCloudSql(Registrar registrar) {
RegistrarDao.saveNew(registrar);
}
@Nullable
@Override
Registrar getOldRegistrar(final String clientId) {
@@ -67,11 +67,9 @@ final class CreateReservedListCommand extends CreateOrUpdateReservedListCommand
.setLastUpdateTime(now)
.build();
stageEntityChange(null, reservedList);
if (alsoCloudSql) {
cloudSqlReservedList =
google.registry.schema.tld.ReservedList.create(
name, shouldPublish, parseToReservationsByLabels(allLines));
}
cloudSqlReservedList =
google.registry.schema.tld.ReservedList.create(
name, shouldPublish, parseToReservationsByLabels(allLines));
}
@Override
@@ -32,12 +32,14 @@ import google.registry.model.registry.RegistryLockDao;
import google.registry.model.reporting.HistoryEntry;
import google.registry.schema.domain.RegistryLock;
import google.registry.util.Clock;
import google.registry.util.StringGenerator;
import java.util.Optional;
import java.util.UUID;
import javax.annotation.Nullable;
import javax.inject.Inject;
import javax.inject.Named;
/**
* Utility class for validating and applying {@link RegistryLock}s.
* Utility functions for validating and applying {@link RegistryLock}s.
*
* <p>For both locks and unlocks, a lock must be requested via the createRegistry*Requst methods
* then verified through the verifyAndApply* methods. These methods will verify that the domain in
@@ -45,9 +47,16 @@ import javax.annotation.Nullable;
*/
public final class DomainLockUtils {
private DomainLockUtils() {}
private static final int VERIFICATION_CODE_LENGTH = 32;
public static RegistryLock createRegistryLockRequest(
private final StringGenerator stringGenerator;
@Inject
public DomainLockUtils(@Named("base58StringGenerator") StringGenerator stringGenerator) {
this.stringGenerator = stringGenerator;
}
public RegistryLock createRegistryLockRequest(
String domainName,
String registrarId,
@Nullable String registrarPocId,
@@ -68,7 +77,7 @@ public final class DomainLockUtils {
RegistryLock lock =
new RegistryLock.Builder()
.setVerificationCode(UUID.randomUUID().toString())
.setVerificationCode(stringGenerator.createString(VERIFICATION_CODE_LENGTH))
.setDomainName(domainName)
.setRepoId(domainBase.getRepoId())
.setRegistrarId(registrarId)
@@ -78,7 +87,7 @@ public final class DomainLockUtils {
return RegistryLockDao.save(lock);
}
public static RegistryLock createRegistryUnlockRequest(
public RegistryLock createRegistryUnlockRequest(
String domainName, String registrarId, boolean isAdmin, Clock clock) {
DomainBase domainBase = getDomain(domainName, clock);
Optional<RegistryLock> lockOptional =
@@ -121,7 +130,7 @@ public final class DomainLockUtils {
}
RegistryLock newLock =
newLockBuilder
.setVerificationCode(UUID.randomUUID().toString())
.setVerificationCode(stringGenerator.createString(VERIFICATION_CODE_LENGTH))
.isSuperuser(isAdmin)
.setUnlockRequestTimestamp(clock.nowUtc())
.setRegistrarId(registrarId)
@@ -129,8 +138,7 @@ public final class DomainLockUtils {
return RegistryLockDao.save(newLock);
}
public static RegistryLock verifyAndApplyLock(
String verificationCode, boolean isAdmin, Clock clock) {
public RegistryLock verifyAndApplyLock(String verificationCode, boolean isAdmin, Clock clock) {
return jpaTm()
.transact(
() -> {
@@ -156,8 +164,7 @@ public final class DomainLockUtils {
});
}
public static RegistryLock verifyAndApplyUnlock(
String verificationCode, boolean isAdmin, Clock clock) {
public RegistryLock verifyAndApplyUnlock(String verificationCode, boolean isAdmin, Clock clock) {
return jpaTm()
.transact(
() -> {
@@ -60,11 +60,11 @@ public class LockDomainCommand extends LockOrUnlockDomainCommand {
@Override
protected RegistryLock createLock(String domain) {
return DomainLockUtils.createRegistryLockRequest(domain, clientId, null, true, clock);
return domainLockUtils.createRegistryLockRequest(domain, clientId, null, true, clock);
}
@Override
protected void finalizeLockOrUnlockRequest(RegistryLock lock) {
DomainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), true, clock);
domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), true, clock);
}
}
@@ -57,6 +57,8 @@ public abstract class LockOrUnlockDomainCommand extends ConfirmingCommand
@Inject Clock clock;
@Inject DomainLockUtils domainLockUtils;
protected ImmutableSet<String> relevantDomains = ImmutableSet.of();
protected ImmutableSet<String> getDomains() {
@@ -20,6 +20,7 @@ import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Strings.emptyToNull;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static google.registry.model.ofy.ObjectifyService.ofy;
import static google.registry.persistence.transaction.TransactionManagerFactory.tm;
import static google.registry.util.DatastoreServiceUtils.getNameOrId;
@@ -45,9 +46,9 @@ import javax.annotation.Nullable;
public abstract class MutatingCommand extends ConfirmingCommand implements CommandWithRemoteApi {
/**
* A mutation of a specific entity, represented by an old and a new version of the entity.
* Storing the old version is necessary to enable checking that the existing entity has not been
* modified when applying a mutation that was created outside the same transaction.
* A mutation of a specific entity, represented by an old and a new version of the entity. Storing
* the old version is necessary to enable checking that the existing entity has not been modified
* when applying a mutation that was created outside the same transaction.
*/
private static class EntityChange {
@@ -169,8 +170,8 @@ public abstract class MutatingCommand extends ConfirmingCommand implements Comma
}
/**
* Returns a set of lists of EntityChange actions to commit. Each list should be executed in
* order inside a single transaction.
* Returns a set of lists of EntityChange actions to commit. Each list should be executed in order
* inside a single transaction.
*/
private ImmutableSet<ImmutableList<EntityChange>> getCollatedEntityChangeBatches() {
ImmutableSet.Builder<ImmutableList<EntityChange>> batches = new ImmutableSet.Builder<>();
@@ -221,4 +222,11 @@ public abstract class MutatingCommand extends ConfirmingCommand implements Comma
? "No entity changes to apply."
: changedEntitiesMap.values().stream().map(Object::toString).collect(joining("\n"));
}
/** Returns the collection of the new entity in the {@link EntityChange}. */
protected ImmutableList<ImmutableObject> getChangedEntities() {
return changedEntitiesMap.values().stream()
.map(entityChange -> entityChange.newEntity)
.collect(toImmutableList());
}
}
@@ -60,11 +60,11 @@ public class UnlockDomainCommand extends LockOrUnlockDomainCommand {
@Override
protected RegistryLock createLock(String domain) {
return DomainLockUtils.createRegistryUnlockRequest(domain, clientId, true, clock);
return domainLockUtils.createRegistryUnlockRequest(domain, clientId, true, clock);
}
@Override
protected void finalizeLockOrUnlockRequest(RegistryLock lock) {
DomainLockUtils.verifyAndApplyUnlock(lock.getVerificationCode(), true, clock);
domainLockUtils.verifyAndApplyUnlock(lock.getVerificationCode(), true, clock);
}
}
@@ -20,6 +20,7 @@ import static google.registry.util.PreconditionsUtils.checkArgumentPresent;
import com.beust.jcommander.Parameters;
import google.registry.config.RegistryEnvironment;
import google.registry.model.registrar.Registrar;
import google.registry.schema.registrar.RegistrarDao;
import javax.annotation.Nullable;
/** Command to update a Registrar. */
@@ -49,4 +50,9 @@ final class UpdateRegistrarCommand extends CreateOrUpdateRegistrarCommand {
+ " contact.");
}
}
@Override
void saveToCloudSql(Registrar registrar) {
RegistrarDao.update(registrar);
}
}
@@ -50,11 +50,9 @@ final class UpdateReservedListCommand extends CreateOrUpdateReservedListCommand
.setLastUpdateTime(new SystemClock().nowUtc())
.setShouldPublish(shouldPublish);
stageEntityChange(existing.get(), updated.build());
if (alsoCloudSql) {
cloudSqlReservedList =
google.registry.schema.tld.ReservedList.create(
name, shouldPublish, parseToReservationsByLabels(allLines));
}
cloudSqlReservedList =
google.registry.schema.tld.ReservedList.create(
name, shouldPublish, parseToReservationsByLabels(allLines));
}
@Override
@@ -37,11 +37,6 @@ final class UploadClaimsListCommand extends ConfirmingCommand implements Command
@Parameter(description = "Claims list filename")
private List<String> mainParameters = new ArrayList<>();
@Parameter(
names = {"--also_cloud_sql"},
description = "Persist claims list to Cloud SQL in addition to Datastore; defaults to false.")
boolean alsoCloudSql;
private String claimsListFilename;
private ClaimsList claimsList;
@@ -64,9 +59,7 @@ final class UploadClaimsListCommand extends ConfirmingCommand implements Command
@Override
public String execute() {
ClaimsListShard.create(claimsList.getTmdbGenerationTime(), claimsList.getLabelsToKeys()).save();
if (alsoCloudSql) {
ClaimsListDao.trySave(claimsList);
}
ClaimsListDao.trySave(claimsList);
return String.format("Successfully uploaded claims list %s", claimsListFilename);
}
}
@@ -119,8 +119,9 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
// handler, registrar-settings really only supports read and update.
String op = Optional.ofNullable((String) input.get(OP_PARAM)).orElse("read");
@SuppressWarnings("unchecked")
Map<String, ?> args = (Map<String, Object>)
Optional.<Object>ofNullable(input.get(ARGS_PARAM)).orElse(ImmutableMap.of());
Map<String, ?> args =
(Map<String, Object>)
Optional.<Object>ofNullable(input.get(ARGS_PARAM)).orElse(ImmutableMap.of());
logger.atInfo().log("Received request '%s' on registrar '%s' with args %s", op, clientId, args);
String status = "SUCCESS";
@@ -296,8 +297,7 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
.ifPresent(builder::setEmailAddress);
builder.setPhoneNumber(
RegistrarFormFields.PHONE_NUMBER_FIELD.extractUntyped(args).orElse(null));
builder.setFaxNumber(
RegistrarFormFields.FAX_NUMBER_FIELD.extractUntyped(args).orElse(null));
builder.setFaxNumber(RegistrarFormFields.FAX_NUMBER_FIELD.extractUntyped(args).orElse(null));
builder.setLocalizedAddress(
RegistrarFormFields.L10N_ADDRESS_FIELD.extractUntyped(args).orElse(null));
@@ -357,9 +357,7 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
* <p>On success, returns {@code builder.build()}.
*/
private Registrar checkNotChangedUnlessAllowed(
Registrar.Builder builder,
Registrar originalRegistrar,
Role allowedRole) {
Registrar.Builder builder, Registrar originalRegistrar, Role allowedRole) {
Registrar updatedRegistrar = builder.build();
if (updatedRegistrar.equals(originalRegistrar)) {
return updatedRegistrar;
@@ -374,9 +372,7 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
}
Map<?, ?> diffs =
DiffUtils.deepDiff(
originalRegistrar.toDiffableFieldMap(),
updatedRegistrar.toDiffableFieldMap(),
true);
originalRegistrar.toDiffableFieldMap(), updatedRegistrar.toDiffableFieldMap(), true);
throw new ForbiddenException(
String.format("Unauthorized: only %s can change fields %s", allowedRole, diffs.keySet()));
}
@@ -400,9 +396,10 @@ public class RegistrarSettingsAction implements Runnable, JsonActionRunner.JsonA
Set<String> emails = new HashSet<>();
for (RegistrarContact contact : updatedContacts) {
if (!emails.add(contact.getEmailAddress())) {
throw new ContactRequirementException(String.format(
"One email address (%s) cannot be used for multiple contacts",
contact.getEmailAddress()));
throw new ContactRequirementException(
String.format(
"One email address (%s) cannot be used for multiple contacts",
contact.getEmailAddress()));
}
}
// Check that required contacts don't go away, once they are set.
@@ -0,0 +1,216 @@
// Copyright 2020 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.registrar;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import static google.registry.security.JsonResponseHelper.Status.ERROR;
import static google.registry.security.JsonResponseHelper.Status.SUCCESS;
import static google.registry.ui.server.registrar.RegistrarConsoleModule.PARAM_CLIENT_ID;
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
import com.google.common.base.Strings;
import com.google.common.base.Throwables;
import com.google.common.collect.ImmutableList;
import com.google.common.flogger.FluentLogger;
import com.google.gson.Gson;
import google.registry.config.RegistryConfig;
import google.registry.config.RegistryConfig.Config;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarContact;
import google.registry.request.Action;
import google.registry.request.Action.Method;
import google.registry.request.HttpException.ForbiddenException;
import google.registry.request.JsonActionRunner;
import google.registry.request.auth.Auth;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.request.auth.AuthenticatedRegistrarAccessor.RegistrarAccessDeniedException;
import google.registry.request.auth.UserAuthInfo;
import google.registry.schema.domain.RegistryLock;
import google.registry.security.JsonResponseHelper;
import google.registry.tools.DomainLockUtils;
import google.registry.util.Clock;
import google.registry.util.EmailMessage;
import google.registry.util.SendEmailService;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.Map;
import java.util.Optional;
import javax.inject.Inject;
import javax.mail.internet.AddressException;
import javax.mail.internet.InternetAddress;
import org.apache.http.client.utils.URIBuilder;
/**
* UI action that allows for creating registry locks. Locks / unlocks must be verified separately
* before they are written permanently.
*
* <p>Note: at the moment we have no mechanism for JSON GET/POSTs in the same class or at the same
* URL, which is why this is distinct from the {@link RegistryLockGetAction}.
*/
@Action(
service = Action.Service.DEFAULT,
path = RegistryLockPostAction.PATH,
method = Method.POST,
auth = Auth.AUTH_PUBLIC_LOGGED_IN)
public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAction {
public static final String PATH = "/registry-lock-post";
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private static final Gson GSON = new Gson();
private static final URL URL_BASE = RegistryConfig.getDefaultServer();
private static final String VERIFICATION_EMAIL_TEMPLATE =
"Please click the link below to perform the lock / unlock action on domain %s. Note: "
+ "this code will expire in one hour.\n\n%s";
private final JsonActionRunner jsonActionRunner;
private final AuthResult authResult;
private final AuthenticatedRegistrarAccessor registrarAccessor;
private final SendEmailService sendEmailService;
private final Clock clock;
private final DomainLockUtils domainLockUtils;
private final InternetAddress gSuiteOutgoingEmailAddress;
@Inject
RegistryLockPostAction(
JsonActionRunner jsonActionRunner,
AuthResult authResult,
AuthenticatedRegistrarAccessor registrarAccessor,
SendEmailService sendEmailService,
Clock clock,
DomainLockUtils domainLockUtils,
@Config("gSuiteOutgoingEmailAddress") InternetAddress gSuiteOutgoingEmailAddress) {
this.jsonActionRunner = jsonActionRunner;
this.authResult = authResult;
this.registrarAccessor = registrarAccessor;
this.sendEmailService = sendEmailService;
this.clock = clock;
this.domainLockUtils = domainLockUtils;
this.gSuiteOutgoingEmailAddress = gSuiteOutgoingEmailAddress;
}
@Override
public void run() {
jsonActionRunner.run(this);
}
@Override
public Map<String, ?> handleJsonRequest(Map<String, ?> input) {
try {
checkArgumentNotNull(input, "Null JSON");
RegistryLockPostInput postInput =
GSON.fromJson(GSON.toJsonTree(input), RegistryLockPostInput.class);
checkArgument(
!Strings.isNullOrEmpty(postInput.clientId),
"Missing key for client: %s",
PARAM_CLIENT_ID);
checkArgument(
!Strings.isNullOrEmpty(postInput.fullyQualifiedDomainName),
"Missing key for fullyQualifiedDomainName");
checkNotNull(postInput.isLock, "Missing key for isLock");
UserAuthInfo userAuthInfo =
authResult
.userAuthInfo()
.orElseThrow(() -> new ForbiddenException("User is not logged in"));
boolean isAdmin = userAuthInfo.isUserAdmin();
String userEmail = userAuthInfo.user().getEmail();
if (!isAdmin) {
verifyRegistryLockPassword(postInput, userEmail);
}
jpaTm()
.transact(
() -> {
RegistryLock registryLock =
postInput.isLock
? domainLockUtils.createRegistryLockRequest(
postInput.fullyQualifiedDomainName,
postInput.clientId,
userEmail,
isAdmin,
clock)
: domainLockUtils.createRegistryUnlockRequest(
postInput.fullyQualifiedDomainName, postInput.clientId, isAdmin, clock);
sendVerificationEmail(registryLock, userEmail, postInput.isLock);
});
String action = postInput.isLock ? "lock" : "unlock";
return JsonResponseHelper.create(SUCCESS, String.format("Successful %s", action));
} catch (Throwable e) {
logger.atWarning().withCause(e).log("Failed to lock/unlock domain with input %s", input);
return JsonResponseHelper.create(
ERROR,
Optional.ofNullable(Throwables.getRootCause(e).getMessage()).orElse("Unspecified error"));
}
}
private void sendVerificationEmail(RegistryLock lock, String userEmail, boolean isLock) {
try {
String url =
new URIBuilder()
.setScheme("https")
.setHost(URL_BASE.getHost())
.setPath("registry-lock-verify")
.setParameter("lockVerificationCode", lock.getVerificationCode())
.setParameter("isLock", String.valueOf(isLock))
.build()
.toString();
String body = String.format(VERIFICATION_EMAIL_TEMPLATE, lock.getDomainName(), url);
ImmutableList<InternetAddress> recipients =
ImmutableList.of(new InternetAddress(userEmail, true));
String action = isLock ? "lock" : "unlock";
sendEmailService.sendEmail(
EmailMessage.newBuilder()
.setBody(body)
.setSubject(String.format("Registry %s verification", action))
.setRecipients(recipients)
.setFrom(gSuiteOutgoingEmailAddress)
.build());
} catch (AddressException | URISyntaxException e) {
throw new RuntimeException(e); // caught above -- this is so we can run in a transaction
}
}
private void verifyRegistryLockPassword(RegistryLockPostInput postInput, String userEmail)
throws RegistrarAccessDeniedException {
// Verify that the user can access the registrar and that the user has
// registry lock enabled and provided a correct password
Registrar registrar = registrarAccessor.getRegistrar(postInput.clientId);
checkArgument(
registrar.isRegistryLockAllowed(), "Registry lock not allowed for this registrar");
checkArgument(!Strings.isNullOrEmpty(postInput.password), "Missing key for password");
RegistrarContact registrarContact =
registrar.getContacts().stream()
.filter(contact -> contact.getEmailAddress().equals(userEmail))
.findFirst()
.orElseThrow(
() ->
new IllegalArgumentException(
String.format("Unknown user email %s", userEmail)));
checkArgument(
registrarContact.verifyRegistryLockPassword(postInput.password),
"Incorrect registry lock password for contact");
}
/** Value class that represents the expected input body from the UI request. */
private static class RegistryLockPostInput {
private String clientId;
private String fullyQualifiedDomainName;
private Boolean isLock;
private String password;
}
}
@@ -49,15 +49,18 @@ public final class RegistryLockVerifyAction extends HtmlAction {
google.registry.ui.soy.registrar.RegistryLockVerificationSoyInfo.getInstance());
private final Clock clock;
private final DomainLockUtils domainLockUtils;
private final String lockVerificationCode;
private final Boolean isLock;
@Inject
public RegistryLockVerifyAction(
Clock clock,
DomainLockUtils domainLockUtils,
@Parameter("lockVerificationCode") String lockVerificationCode,
@Parameter("isLock") Boolean isLock) {
this.clock = clock;
this.domainLockUtils = domainLockUtils;
this.lockVerificationCode = lockVerificationCode;
this.isLock = isLock;
}
@@ -68,9 +71,9 @@ public final class RegistryLockVerifyAction extends HtmlAction {
boolean isAdmin = authResult.userAuthInfo().get().isUserAdmin();
final RegistryLock resultLock;
if (isLock) {
resultLock = DomainLockUtils.verifyAndApplyLock(lockVerificationCode, isAdmin, clock);
resultLock = domainLockUtils.verifyAndApplyLock(lockVerificationCode, isAdmin, clock);
} else {
resultLock = DomainLockUtils.verifyAndApplyUnlock(lockVerificationCode, isAdmin, clock);
resultLock = domainLockUtils.verifyAndApplyUnlock(lockVerificationCode, isAdmin, clock);
}
data.put("isLock", isLock);
data.put("success", true);
@@ -21,28 +21,27 @@
-->
<class>google.registry.model.domain.DomainBase</class>
<class>google.registry.model.registrar.Registrar</class>
<class>google.registry.model.registrar.RegistrarContact</class>
<class>google.registry.schema.domain.RegistryLock</class>
<class>google.registry.schema.tmch.ClaimsList</class>
<class>google.registry.schema.cursor.Cursor</class>
<class>google.registry.model.transfer.BaseTransferObject</class>
<class>google.registry.schema.server.Lock</class>
<class>google.registry.schema.tld.PremiumList</class>
<class>google.registry.schema.tld.PremiumEntry</class>
<class>google.registry.schema.tld.ReservedList</class>
<class>google.registry.model.domain.secdns.DelegationSignerData</class>
<class>google.registry.model.domain.DesignatedContact</class>
<class>google.registry.model.domain.DomainBase</class>
<class>google.registry.model.domain.GracePeriod</class>
<class>org.joda.time.Period</class>
<class>google.registry.model.transfer.TransferData</class>
<class>google.registry.model.eppcommon.Trid</class>
<!-- Customized type converters -->
<class>google.registry.persistence.BloomFilterConverter</class>
<class>google.registry.persistence.CidrAddressBlockListConverter</class>
<class>google.registry.persistence.CreateAutoTimestampConverter</class>
<class>google.registry.persistence.CurrencyUnitConverter</class>
<class>google.registry.persistence.DateTimeConverter</class>
<class>google.registry.persistence.RegistrarStateConverter</class>
<class>google.registry.persistence.RegistrarTypeConverter</class>
<class>google.registry.persistence.RegistrarPocSetConverter</class>
<class>google.registry.persistence.StatusValueSetConverter</class>
<class>google.registry.persistence.StringListConverter</class>
<class>google.registry.persistence.StringSetConverter</class>
<class>google.registry.persistence.UpdateAutoTimestampConverter</class>
<class>google.registry.persistence.ZonedDateTimeConverter</class>
@@ -26,7 +26,9 @@ public class DevTool {
* any invocations in scripts (e.g. PDT, ICANN reporting).
*/
public static final ImmutableMap<String, Class<? extends Command>> COMMAND_MAP =
ImmutableMap.of("generate_sql_schema", GenerateSqlSchemaCommand.class);
ImmutableMap.of(
"dump_golden_schema", DumpGoldenSchemaCommand.class,
"generate_sql_schema", GenerateSqlSchemaCommand.class);
public static void main(String[] args) throws Exception {
RegistryToolEnvironment.parseFromArgs(args).setup();
@@ -0,0 +1,91 @@
// Copyright 2020 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.tools;
import com.beust.jcommander.Parameter;
import com.beust.jcommander.Parameters;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.file.Path;
import org.flywaydb.core.Flyway;
import org.testcontainers.containers.BindMode;
import org.testcontainers.containers.Container;
/**
* Generates a schema for JPA annotated classes using Hibernate.
*
* <p>Note that this isn't complete yet, as all of the persistent classes have not yet been
* converted. After converting a class, a call to "addAnnotatedClass()" for the new class must be
* added to the code below.
*/
@Parameters(separators = " =", commandDescription = "Dump golden schema.")
public class DumpGoldenSchemaCommand extends PostgresqlCommand {
// The mount point in the container.
private static final String CONTAINER_MOUNT_POINT = "/tmp/pg_dump.out";
@Parameter(
names = {"--output", "-o"},
description = "Output file",
required = true)
Path output;
@Override
void runCommand() throws IOException, InterruptedException {
Flyway flyway =
Flyway.configure()
.locations("sql/flyway")
.dataSource(
postgresContainer.getJdbcUrl(),
postgresContainer.getUsername(),
postgresContainer.getPassword())
.load();
flyway.migrate();
String userName = postgresContainer.getUsername();
String databaseName = postgresContainer.getDatabaseName();
Container.ExecResult result =
postgresContainer.execInContainer(getSchemaDumpCommand(userName, databaseName));
if (result.getExitCode() != 0) {
throw new RuntimeException(result.toString());
}
}
@Override
protected void onContainerCreate() throws IOException {
// open the output file for write so we can mount it.
new FileOutputStream(output.toFile()).close();
postgresContainer.withFileSystemBind(
output.toString(), CONTAINER_MOUNT_POINT, BindMode.READ_WRITE);
}
private static String[] getSchemaDumpCommand(String username, String dbName) {
return new String[] {
"pg_dump",
"-h",
"localhost",
"-U",
username,
"-f",
CONTAINER_MOUNT_POINT,
"--schema-only",
"--no-owner",
"--no-privileges",
"--exclude-table",
"flyway_schema_history",
dbName
};
}
}
@@ -0,0 +1,128 @@
// Copyright 2019 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.tools;
import com.beust.jcommander.Parameter;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.flogger.FluentLogger;
import google.registry.persistence.NomulusPostgreSql;
import org.testcontainers.containers.PostgreSQLContainer;
/** Base class for commands that need a PostgreSQL database. */
public abstract class PostgresqlCommand implements Command {
static final FluentLogger logger = FluentLogger.forEnclosingClass();
protected static final String DB_NAME = "postgres";
protected static final String DB_USERNAME = "postgres";
protected static final String DB_PASSWORD = "domain-registry";
@VisibleForTesting
public static final String DB_OPTIONS_CLASH =
"Database host and port may not be specified along with the option to start a "
+ "PostgreSQL container.";
@VisibleForTesting public static final int POSTGRESQL_PORT = 5432;
protected PostgreSQLContainer postgresContainer = null;
@Parameter(
names = {"-s", "--start_postgresql"},
description = "If specified, start PostgreSQL in a Docker container.")
boolean startPostgresql = false;
@Parameter(
names = {"-a", "--db_host"},
description = "Database host name.")
String databaseHost;
@Parameter(
names = {"-p", "--db_port"},
description = "Database port number. This defaults to the PostgreSQL default port.")
Integer databasePort;
/**
* Starts the database if appropriate.
*
* <p>Returns true if the database was successfully initialized, false if not.
*/
private boolean initializeDatabase() {
// Start PostgreSQL if requested.
if (startPostgresql) {
// Complain if the user has also specified either --db_host or --db_port.
if (databaseHost != null || databasePort != null) {
System.err.println(DB_OPTIONS_CLASH);
// TODO: it would be nice to exit(1) here, but this breaks testability.
return false;
}
// Start the container and store the address information.
postgresContainer =
new PostgreSQLContainer(NomulusPostgreSql.getDockerTag())
.withDatabaseName(DB_NAME)
.withUsername(DB_USERNAME)
.withPassword(DB_PASSWORD);
try {
onContainerCreate();
} catch (Exception e) {
logger.atSevere().withCause(e).log("Error in container callback hook.");
return false;
}
postgresContainer.start();
databaseHost = postgresContainer.getContainerIpAddress();
databasePort = postgresContainer.getMappedPort(POSTGRESQL_PORT);
} else if (databaseHost == null) {
System.err.println(
"You must specify either --start_postgresql to start a PostgreSQL database in a\n"
+ "docker instance, or specify --db_host (and, optionally, --db_port) to identify\n"
+ "the location of a running instance. To start a long-lived instance (suitable\n"
+ "for running this command multiple times) run this:\n\n"
+ " docker run --rm --name some-postgres -e POSTGRES_PASSWORD=domain-registry \\\n"
+ " -d "
+ NomulusPostgreSql.getDockerTag()
+ "\n\nCopy the container id output from the command, then run:\n\n"
+ " docker inspect <container-id> | grep IPAddress\n\n"
+ "To obtain the value for --db-host.\n");
// TODO(mmuller): need exit(1), see above.
return false;
}
// use the default port if non has been defined.
if (databasePort == null) {
databasePort = POSTGRESQL_PORT;
}
return true;
}
@Override
public void run() throws Exception {
if (!initializeDatabase()) {
return;
}
try {
runCommand();
} finally {
if (postgresContainer != null) {
postgresContainer.stop();
}
}
}
/** Called after the container has been created but before it has been started. */
protected void onContainerCreate() throws Exception {}
/** Command to be run while the database is running. */
abstract void runCommand() throws Exception;
}
@@ -0,0 +1,79 @@
// Copyright 2020 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.model.eppcommon;
import static com.google.common.truth.Truth.assertThat;
import com.google.common.collect.ImmutableList;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Tests for {@link Address}. */
@RunWith(JUnit4.class)
public class AddressTest {
@Test
public void onLoad_setsIndividualStreetLinesSuccessfully() {
Address address = new Address();
address.onLoad(ImmutableList.of("line1", "line2", "line3"));
assertThat(address.streetLine1).isEqualTo("line1");
assertThat(address.streetLine2).isEqualTo("line2");
assertThat(address.streetLine3).isEqualTo("line3");
}
@Test
public void onLoad_setsOnlyNonNullStreetLines() {
Address address = new Address();
address.onLoad(ImmutableList.of("line1", "line2"));
assertThat(address.streetLine1).isEqualTo("line1");
assertThat(address.streetLine2).isEqualTo("line2");
assertThat(address.streetLine3).isNull();
}
@Test
public void onLoad_doNothingIfInputIsNull() {
Address address = new Address();
address.onLoad(null);
assertThat(address.streetLine1).isNull();
assertThat(address.streetLine2).isNull();
assertThat(address.streetLine3).isNull();
}
@Test
public void postLoad_setsStreetListSuccessfully() {
Address address = new Address();
address.streetLine1 = "line1";
address.streetLine2 = "line2";
address.streetLine3 = "line3";
address.postLoad();
assertThat(address.street).containsExactly("line1", "line2", "line3");
}
@Test
public void postLoad_setsOnlyNonNullStreetLines() {
Address address = new Address();
address.streetLine1 = "line1";
address.streetLine2 = "line2";
address.postLoad();
assertThat(address.street).containsExactly("line1", "line2");
}
@Test
public void postLoad_doNothingIfInputIsNull() {
Address address = new Address();
address.postLoad();
assertThat(address.street).isNull();
}
}
@@ -25,7 +25,6 @@ import google.registry.schema.domain.RegistryLock;
import google.registry.testing.AppEngineRule;
import google.registry.testing.FakeClock;
import java.util.Optional;
import java.util.UUID;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
@@ -201,7 +200,7 @@ public final class RegistryLockDaoTest {
.setRepoId("repoId")
.setDomainName("example.test")
.setRegistrarId("TheRegistrar")
.setVerificationCode(UUID.randomUUID().toString())
.setVerificationCode("123456789ABCDEFGHJKLMNPQRSTUVWXY")
.isSuperuser(true)
.build();
}
@@ -25,13 +25,12 @@ import google.registry.util.CidrAddressBlock;
import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.annotations.Type;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link CidrAddressBlockListUserType}. */
/** Unit tests for {@link CidrAddressBlockListConverter}. */
@RunWith(JUnit4.class)
public class CidrAddressBlockListUserTypeTest {
@Rule
@@ -59,7 +58,6 @@ public class CidrAddressBlockListUserTypeTest {
@Id String name = "id";
@Type(type = "google.registry.persistence.CidrAddressBlockListUserType")
List<CidrAddressBlock> addresses;
private TestEntity() {}
@@ -0,0 +1,67 @@
// Copyright 2020 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.persistence;
import static com.google.common.collect.ImmutableList.toImmutableList;
import static com.google.common.collect.ImmutableSet.toImmutableSet;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.truth.Expect;
import java.util.Collections;
import javax.persistence.AttributeConverter;
import javax.persistence.Entity;
import org.junit.ClassRule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests to verify persistence.xml is valid. */
@RunWith(JUnit4.class)
public class PersistenceXmlTest {
@ClassRule public static final Expect expect = Expect.create();
@Test
public void verifyClassTags_containOnlyRequiredClasses() {
ImmutableList<Class> managedClassed = PersistenceXmlUtility.getManagedClasses();
ImmutableList<Class> unnecessaryClasses =
managedClassed.stream()
.filter(
clazz ->
!clazz.isAnnotationPresent(Entity.class)
&& !AttributeConverter.class.isAssignableFrom(clazz))
.collect(toImmutableList());
ImmutableSet<Class> duplicateClasses =
managedClassed.stream()
.filter(clazz -> Collections.frequency(managedClassed, clazz) > 1)
.collect(toImmutableSet());
expect
.withMessage("Found duplicate <class> tags defined in persistence.xml.")
.that(duplicateClasses)
.isEmpty();
expect
.withMessage(
"Found unnecessary <class> tags defined in persistence.xml. Only entity class and"
+ " implementation of AttributeConverter are required to be added in"
+ " persistence.xml.")
.that(unnecessaryClasses)
.isEmpty();
}
}
@@ -1,76 +0,0 @@
// Copyright 2020 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.persistence;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import google.registry.model.ImmutableObject;
import google.registry.model.registrar.Registrar.Type;
import google.registry.persistence.transaction.JpaTestRules;
import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link RegistrarTypeConverter}. */
@RunWith(JUnit4.class)
public class RegistrarTypeConverterTest {
@Rule
public final JpaUnitTestRule jpaRule =
new JpaTestRules.Builder().withEntityClass(TestEntity.class).buildUnitTestRule();
@Test
public void roundTripConversion_returnsSameEnum() {
TestEntity testEntity = new TestEntity(Type.MONITORING);
jpaTm().transact(() -> jpaTm().getEntityManager().persist(testEntity));
TestEntity persisted =
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "id"));
assertThat(persisted.type).isEqualTo(Type.MONITORING);
}
@Test
public void testNativeQuery_succeeds() {
TestEntity testEntity = new TestEntity(Type.MONITORING);
jpaTm().transact(() -> jpaTm().getEntityManager().persist(testEntity));
assertThat(
jpaTm()
.transact(
() ->
jpaTm()
.getEntityManager()
.createNativeQuery("SELECT type FROM \"TestEntity\" WHERE name = 'id'")
.getSingleResult()))
.isEqualTo("MONITORING");
}
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
private static class TestEntity extends ImmutableObject {
@Id String name = "id";
Type type;
private TestEntity() {}
private TestEntity(Type type) {
this.type = type;
}
}
}
@@ -18,29 +18,27 @@ import static com.google.common.truth.Truth.assertThat;
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
import com.google.common.collect.ImmutableSet;
import google.registry.model.eppcommon.StatusValue;
import google.registry.persistence.transaction.JpaTestRules;
import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.annotations.Type;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link EnumSetUserType}. */
/** Unit tests for {@link StatusValueSetConverter}. */
@RunWith(JUnit4.class)
public class EnumSetUserTypeTest {
public class StatusValueSetConverterTest {
@Rule
public final JpaUnitTestRule jpaRule =
new JpaTestRules.Builder().withEntityClass(TestEntity.class).buildUnitTestRule();
public EnumSetUserTypeTest() {}
@Test
public void testRoundTrip() {
Set<TestEnum> enums = ImmutableSet.of(TestEnum.BAR, TestEnum.FOO);
Set<StatusValue> enums = ImmutableSet.of(StatusValue.INACTIVE, StatusValue.PENDING_DELETE);
TestEntity obj = new TestEntity("foo", enums);
jpaTm().transact(() -> jpaTm().getEntityManager().persist(obj));
@@ -49,29 +47,15 @@ public class EnumSetUserTypeTest {
assertThat(persisted.data).isEqualTo(enums);
}
enum TestEnum {
FOO,
BAR,
BAZ;
public static class TestEnumType extends EnumSetUserType<TestEnum> {
@Override
protected TestEnum convertToElem(String value) {
return TestEnum.valueOf(value);
}
}
}
@Entity(name = "TestEntity")
static class TestEntity {
@Id String name;
@Type(type = "google.registry.persistence.EnumSetUserTypeTest$TestEnum$TestEnumType")
Set<TestEnum> data;
Set<StatusValue> data;
TestEntity() {}
TestEntity(String name, Set<TestEnum> data) {
TestEntity(String name, Set<StatusValue> data) {
this.name = name;
this.data = data;
}
@@ -26,15 +26,14 @@ import java.util.List;
import javax.persistence.Entity;
import javax.persistence.Id;
import javax.persistence.NoResultException;
import org.hibernate.annotations.Type;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link StringListUserType}. */
/** Unit tests for {@link StringListConverter}. */
@RunWith(JUnit4.class)
public class StringListUserTypeTest {
public class StringListConverterTest {
@Rule
public final JpaUnitTestRule jpaRule =
new JpaTestRules.Builder().withEntityClass(TestEntity.class).buildUnitTestRule();
@@ -123,7 +122,6 @@ public class StringListUserTypeTest {
@Id String name = "id";
@Type(type = "google.registry.persistence.StringListUserType")
List<String> tlds;
private TestEntity() {}
@@ -24,15 +24,14 @@ import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule;
import java.util.Set;
import javax.persistence.Entity;
import javax.persistence.Id;
import org.hibernate.annotations.Type;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link StringSetUserType}. */
/** Unit tests for {@link StringSetConverter}. */
@RunWith(JUnit4.class)
public class StringSetUserTypeTest {
public class StringSetConverterTest {
@Rule
public final JpaUnitTestRule jpaRule =
new JpaTestRules.Builder().withEntityClass(TestEntity.class).buildUnitTestRule();
@@ -70,7 +69,6 @@ public class StringSetUserTypeTest {
@Id String name = "id";
@Type(type = "google.registry.persistence.StringSetUserType")
Set<String> tlds;
private TestEntity() {}
@@ -22,15 +22,17 @@ import google.registry.model.registrar.Registrar.State;
import google.registry.persistence.transaction.JpaTestRules;
import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Id;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link RegistrarStateConverter}. */
/** Unit tests for {@link Enumerated} annotation. */
@RunWith(JUnit4.class)
public class RegistrarStateConverterTest {
public class StringValueEnumeratedTest {
@Rule
public final JpaUnitTestRule jpaRule =
@@ -66,6 +68,7 @@ public class RegistrarStateConverterTest {
@Id String name = "id";
@Enumerated(EnumType.STRING)
State state;
private TestEntity() {}
@@ -19,13 +19,17 @@ import google.registry.model.domain.DomainBaseSqlTest;
import google.registry.model.registry.RegistryLockDaoTest;
import google.registry.persistence.transaction.JpaEntityCoverage;
import google.registry.schema.cursor.CursorDaoTest;
import google.registry.schema.registrar.RegistrarDaoTest;
import google.registry.schema.server.LockDaoTest;
import google.registry.schema.tld.PremiumListDaoTest;
import google.registry.schema.tld.ReservedListDaoTest;
import google.registry.schema.tmch.ClaimsListDaoTest;
import google.registry.tools.CreateRegistrarCommandTest;
import google.registry.tools.CreateReservedListCommandTest;
import google.registry.tools.DomainLockUtilsTest;
import google.registry.tools.LockDomainCommandTest;
import google.registry.tools.UnlockDomainCommandTest;
import google.registry.tools.UpdateRegistrarCommandTest;
import google.registry.tools.UpdateReservedListCommandTest;
import google.registry.tools.server.CreatePremiumListActionTest;
import google.registry.tools.server.UpdatePremiumListActionTest;
@@ -53,18 +57,22 @@ import org.junit.runners.Suite.SuiteClasses;
@SuiteClasses({
ClaimsListDaoTest.class,
CreatePremiumListActionTest.class,
CreateRegistrarCommandTest.class,
CreateReservedListCommandTest.class,
CursorDaoTest.class,
DomainLockUtilsTest.class,
LockDaoTest.class,
LockDomainCommandTest.class,
DomainBaseSqlTest.class,
PremiumListDaoTest.class,
RegistrarDaoTest.class,
RegistryLockDaoTest.class,
RegistryLockGetActionTest.class,
RegistryLockVerifyActionTest.class,
ReservedListDaoTest.class,
UnlockDomainCommandTest.class,
UpdatePremiumListActionTest.class,
UpdateRegistrarCommandTest.class,
UpdateReservedListCommandTest.class
})
public class SqlIntegrationTestSuite {
@@ -0,0 +1,104 @@
// Copyright 2020 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.schema.registrar;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import com.google.common.collect.ImmutableList;
import google.registry.model.EntityTestCase;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.persistence.transaction.JpaTestRules;
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageRule;
import google.registry.testing.FakeClock;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link RegistrarDao}. */
@RunWith(JUnit4.class)
public class RegistrarDaoTest extends EntityTestCase {
private final FakeClock fakeClock = new FakeClock();
@Rule
public final JpaIntegrationWithCoverageRule jpaRule =
new JpaTestRules.Builder().withClock(fakeClock).buildIntegrationWithCoverageRule();
private Registrar testRegistrar;
@Before
public void setUp() {
testRegistrar =
new Registrar.Builder()
.setType(Registrar.Type.TEST)
.setClientId("registrarId")
.setRegistrarName("registrarName")
.setLocalizedAddress(
new RegistrarAddress.Builder()
.setStreet(ImmutableList.of("123 Example Boulevard."))
.setCity("Williamsburg")
.setState("NY")
.setZip("11211")
.setCountryCode("US")
.build())
.build();
}
@Test
public void saveNew_worksSuccessfully() {
assertThat(RegistrarDao.checkExists("registrarId")).isFalse();
RegistrarDao.saveNew(testRegistrar);
assertThat(RegistrarDao.checkExists("registrarId")).isTrue();
}
@Test
public void update_worksSuccessfully() {
RegistrarDao.saveNew(testRegistrar);
Registrar persisted = RegistrarDao.load("registrarId").get();
assertThat(persisted.getRegistrarName()).isEqualTo("registrarName");
RegistrarDao.update(persisted.asBuilder().setRegistrarName("changedRegistrarName").build());
persisted = RegistrarDao.load("registrarId").get();
assertThat(persisted.getRegistrarName()).isEqualTo("changedRegistrarName");
}
@Test
public void update_throwsExceptionWhenEntityDoesNotExist() {
assertThat(RegistrarDao.checkExists("registrarId")).isFalse();
assertThrows(IllegalArgumentException.class, () -> RegistrarDao.update(testRegistrar));
}
@Test
public void load_worksSuccessfully() {
assertThat(RegistrarDao.checkExists("registrarId")).isFalse();
RegistrarDao.saveNew(testRegistrar);
Registrar persisted = RegistrarDao.load("registrarId").get();
assertThat(persisted.getClientId()).isEqualTo("registrarId");
assertThat(persisted.getRegistrarName()).isEqualTo("registrarName");
assertThat(persisted.getCreationTime()).isEqualTo(fakeClock.nowUtc());
assertThat(persisted.getLocalizedAddress())
.isEqualTo(
new RegistrarAddress.Builder()
.setStreet(ImmutableList.of("123 Example Boulevard."))
.setCity("Williamsburg")
.setState("NY")
.setZip("11211")
.setCountryCode("US")
.build());
}
}
@@ -0,0 +1,129 @@
// Copyright 2020 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.schema.server;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import google.registry.persistence.transaction.JpaTestRules;
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageRule;
import google.registry.testing.FakeClock;
import java.util.Optional;
import javax.persistence.RollbackException;
import org.joda.time.Duration;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
/** Unit tests for {@link Lock}. */
@RunWith(JUnit4.class)
public class LockDaoTest {
private final FakeClock fakeClock = new FakeClock();
@Rule
public final JpaIntegrationWithCoverageRule jpaRule =
new JpaTestRules.Builder().withClock(fakeClock).buildIntegrationWithCoverageRule();
@Test
public void save_worksSuccessfully() {
Lock lock =
Lock.create("testResource", "tld", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
LockDao.saveNew(lock);
Optional<Lock> returnedLock = LockDao.load("testResource", "tld");
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
assertThat(returnedLock.get().requestLogId).isEqualTo(lock.requestLogId);
}
@Test
public void save_failsWhenLockAlreadyExists() {
Lock lock =
Lock.create("testResource", "tld", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
LockDao.saveNew(lock);
Lock lock2 =
Lock.create("testResource", "tld", "testLogId2", fakeClock.nowUtc(), Duration.millis(4));
RollbackException thrown = assertThrows(RollbackException.class, () -> LockDao.saveNew(lock2));
assertThat(thrown.getCause().getCause().getCause().getMessage())
.contains("duplicate key value violates unique constraint");
}
@Test
public void save_worksSuccesfullyGlobalLock() {
Lock lock =
Lock.createGlobal("testResource", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
LockDao.saveNew(lock);
Optional<Lock> returnedLock = LockDao.load("testResource");
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
assertThat(returnedLock.get().requestLogId).isEqualTo(lock.requestLogId);
}
@Test
public void load_worksSuccessfully() {
Lock lock =
Lock.create("testResource", "tld", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
LockDao.saveNew(lock);
Optional<Lock> returnedLock = LockDao.load("testResource", "tld");
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
assertThat(returnedLock.get().requestLogId).isEqualTo(lock.requestLogId);
}
@Test
public void load_worksSuccessfullyGlobalLock() {
Lock lock =
Lock.createGlobal("testResource", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
LockDao.saveNew(lock);
Optional<Lock> returnedLock = LockDao.load("testResource");
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
assertThat(returnedLock.get().requestLogId).isEqualTo(lock.requestLogId);
}
@Test
public void load_worksSuccesfullyLockDoesNotExist() {
Optional<Lock> returnedLock = LockDao.load("testResource", "tld");
assertThat(returnedLock.isPresent()).isFalse();
}
@Test
public void delete_worksSuccesfully() {
Lock lock =
Lock.create("testResource", "tld", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
LockDao.saveNew(lock);
Optional<Lock> returnedLock = LockDao.load("testResource", "tld");
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
LockDao.delete(lock);
returnedLock = LockDao.load("testResource", "tld");
assertThat(returnedLock.isPresent()).isFalse();
}
@Test
public void delete_worksSuccessfullyGlobalLock() {
Lock lock =
Lock.createGlobal("testResource", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
LockDao.saveNew(lock);
Optional<Lock> returnedLock = LockDao.load("testResource");
assertThat(returnedLock.get().expirationTime).isEqualTo(lock.expirationTime);
LockDao.delete(lock);
returnedLock = LockDao.load("testResource");
assertThat(returnedLock.isPresent()).isFalse();
}
@Test
public void delete_succeedsLockDoesntExist() {
Lock lock =
Lock.createGlobal("testResource", "testLogId", fakeClock.nowUtc(), Duration.millis(2));
LockDao.delete(lock);
}
}
@@ -84,6 +84,7 @@ public final class RegistryTestServer {
route("/registrar-ote-status", FrontendServlet.class),
route("/registrar-settings", FrontendServlet.class),
route("/registry-lock-get", FrontendServlet.class),
route("/registry-lock-post", FrontendServlet.class),
route("/registry-lock-verify", FrontendServlet.class));
private static final ImmutableList<Class<? extends Filter>> FILTERS = ImmutableList.of(
@@ -33,12 +33,17 @@ import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Range;
import com.google.common.net.MediaType;
import google.registry.model.registrar.Registrar;
import google.registry.persistence.transaction.JpaTestRules;
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageRule;
import google.registry.schema.registrar.RegistrarDao;
import google.registry.testing.CertificateSamples;
import google.registry.testing.FakeClock;
import java.io.IOException;
import java.util.Optional;
import org.joda.money.CurrencyUnit;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.mockito.ArgumentMatchers;
import org.mockito.Mock;
@@ -46,6 +51,12 @@ import org.mockito.Mock;
/** Unit tests for {@link CreateRegistrarCommand}. */
public class CreateRegistrarCommandTest extends CommandTestCase<CreateRegistrarCommand> {
private final FakeClock fakeClock = new FakeClock();
@Rule
public final JpaIntegrationWithCoverageRule jpaRule =
new JpaTestRules.Builder().withClock(fakeClock).buildIntegrationWithCoverageRule();
@Mock private AppEngineConnection connection;
@Before
@@ -100,6 +111,28 @@ public class CreateRegistrarCommandTest extends CommandTestCase<CreateRegistrarC
eq(new byte[0]));
}
@Test
public void testSuccess_alsoSaveToCloudSql() throws Exception {
runCommandForced(
"--name=blobio",
"--password=\"some_password\"",
"--registrar_type=REAL",
"--iana_id=8",
"--passcode=01234",
"--icann_referral_email=foo@bar.test",
"--street=\"123 Fake St\"",
"--city Fakington",
"--state MA",
"--zip 00351",
"--cc US",
"clientz");
Optional<Registrar> registrar = Registrar.loadByClientId("clientz");
assertThat(registrar).isPresent();
assertThat(registrar.get().verifyPassword("some_password")).isTrue();
assertThat(RegistrarDao.checkExists("clientz")).isTrue();
}
@Test
public void testSuccess_quotedPassword() throws Exception {
runCommandForced(
@@ -178,8 +178,7 @@ public class CreateReservedListCommandTest extends
@Test
public void testSaveToCloudSql_succeeds() throws Exception {
runCommandForced(
"--name=xn--q9jyb4c_common-reserved", "--input=" + reservedTermsPath, "--also_cloud_sql");
runCommandForced("--name=xn--q9jyb4c_common-reserved", "--input=" + reservedTermsPath);
verifyXnq9jyb4cInDatastore();
verifyXnq9jyb4cInCloudSql();
}
@@ -193,8 +192,7 @@ public class CreateReservedListCommandTest extends
"xn--q9jyb4c_common-reserved",
true,
ImmutableMap.of("testdomain", ReservedEntry.create(FULLY_BLOCKED, ""))));
runCommandForced(
"--name=xn--q9jyb4c_common-reserved", "--input=" + reservedTermsPath, "--also_cloud_sql");
runCommandForced("--name=xn--q9jyb4c_common-reserved", "--input=" + reservedTermsPath);
verifyXnq9jyb4cInDatastore();
}
@@ -38,8 +38,10 @@ import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCo
import google.registry.schema.domain.RegistryLock;
import google.registry.testing.AppEngineRule;
import google.registry.testing.DatastoreHelper;
import google.registry.testing.DeterministicStringGenerator;
import google.registry.testing.FakeClock;
import google.registry.testing.UserInfo;
import google.registry.util.StringGenerator.Alphabets;
import java.util.Set;
import java.util.stream.Collectors;
import org.joda.time.Duration;
@@ -57,6 +59,8 @@ public final class DomainLockUtilsTest {
private static final String POC_ID = "marla.singer@example.com";
private final FakeClock clock = new FakeClock();
private final DomainLockUtils domainLockUtils =
new DomainLockUtils(new DeterministicStringGenerator(Alphabets.BASE_58));
@Rule
public final AppEngineRule appEngineRule =
@@ -80,39 +84,39 @@ public final class DomainLockUtilsTest {
@Test
public void testSuccess_createLock() {
DomainLockUtils.createRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock);
domainLockUtils.createRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock);
}
@Test
public void testSuccess_createUnlock() {
RegistryLock lock =
DomainLockUtils.createRegistryLockRequest(
domainLockUtils.createRegistryLockRequest(
DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock);
DomainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false, clock);
DomainLockUtils.createRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false, clock);
domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false, clock);
domainLockUtils.createRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false, clock);
}
@Test
public void testSuccess_createUnlock_adminUnlockingAdmin() {
RegistryLock lock =
DomainLockUtils.createRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", null, true, clock);
DomainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), true, clock);
DomainLockUtils.createRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", true, clock);
domainLockUtils.createRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", null, true, clock);
domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), true, clock);
domainLockUtils.createRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", true, clock);
}
@Test
public void testSuccess_createLock_previousLockExpired() {
DomainLockUtils.createRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock);
domainLockUtils.createRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock);
clock.advanceBy(Duration.standardDays(1));
DomainLockUtils.createRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock);
domainLockUtils.createRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock);
}
@Test
public void testSuccess_applyLockDomain() {
RegistryLock lock =
DomainLockUtils.createRegistryLockRequest(
domainLockUtils.createRegistryLockRequest(
DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock);
DomainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false, clock);
domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false, clock);
assertThat(reloadDomain().getStatusValues()).containsExactlyElementsIn(REGISTRY_LOCK_STATUSES);
HistoryEntry historyEntry = getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_UPDATE);
assertThat(historyEntry.getRequestedByRegistrar()).isTrue();
@@ -125,12 +129,12 @@ public final class DomainLockUtilsTest {
@Test
public void testSuccess_applyUnlockDomain() {
RegistryLock lock =
DomainLockUtils.createRegistryLockRequest(
domainLockUtils.createRegistryLockRequest(
DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock);
DomainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false, clock);
domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false, clock);
RegistryLock unlock =
DomainLockUtils.createRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false, clock);
DomainLockUtils.verifyAndApplyUnlock(unlock.getVerificationCode(), false, clock);
domainLockUtils.createRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false, clock);
domainLockUtils.verifyAndApplyUnlock(unlock.getVerificationCode(), false, clock);
assertThat(reloadDomain().getStatusValues()).containsNoneIn(REGISTRY_LOCK_STATUSES);
ImmutableList<HistoryEntry> historyEntries =
@@ -149,8 +153,8 @@ public final class DomainLockUtilsTest {
@Test
public void testSuccess_applyAdminLock_onlyHistoryEntry() {
RegistryLock lock =
DomainLockUtils.createRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", null, true, clock);
DomainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), true, clock);
domainLockUtils.createRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", null, true, clock);
domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), true, clock);
HistoryEntry historyEntry = getOnlyHistoryEntryOfType(domain, HistoryEntry.Type.DOMAIN_UPDATE);
assertThat(historyEntry.getRequestedByRegistrar()).isFalse();
@@ -161,16 +165,16 @@ public final class DomainLockUtilsTest {
@Test
public void testFailure_createUnlock_alreadyPendingUnlock() {
RegistryLock lock =
DomainLockUtils.createRegistryLockRequest(
domainLockUtils.createRegistryLockRequest(
DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock);
DomainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false, clock);
DomainLockUtils.createRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false, clock);
domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false, clock);
domainLockUtils.createRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false, clock);
assertThat(
assertThrows(
IllegalArgumentException.class,
() ->
DomainLockUtils.createRegistryUnlockRequest(
domainLockUtils.createRegistryUnlockRequest(
DOMAIN_NAME, "TheRegistrar", false, clock)))
.hasMessageThat()
.isEqualTo("A pending unlock action already exists for example.tld");
@@ -179,13 +183,13 @@ public final class DomainLockUtilsTest {
@Test
public void testFailure_createUnlock_nonAdminUnlockingAdmin() {
RegistryLock lock =
DomainLockUtils.createRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", null, true, clock);
DomainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), true, clock);
domainLockUtils.createRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", null, true, clock);
domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), true, clock);
assertThat(
assertThrows(
IllegalArgumentException.class,
() ->
DomainLockUtils.createRegistryUnlockRequest(
domainLockUtils.createRegistryUnlockRequest(
DOMAIN_NAME, "TheRegistrar", false, clock)))
.hasMessageThat()
.isEqualTo("Non-admin user cannot unlock admin-locked domain example.tld");
@@ -197,7 +201,7 @@ public final class DomainLockUtilsTest {
assertThrows(
IllegalArgumentException.class,
() ->
DomainLockUtils.createRegistryLockRequest(
domainLockUtils.createRegistryLockRequest(
"asdf.tld", "TheRegistrar", POC_ID, false, clock)))
.hasMessageThat()
.isEqualTo("Unknown domain asdf.tld");
@@ -205,12 +209,12 @@ public final class DomainLockUtilsTest {
@Test
public void testFailure_createLock_alreadyPendingLock() {
DomainLockUtils.createRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock);
domainLockUtils.createRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock);
assertThat(
assertThrows(
IllegalArgumentException.class,
() ->
DomainLockUtils.createRegistryLockRequest(
domainLockUtils.createRegistryLockRequest(
DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock)))
.hasMessageThat()
.isEqualTo("A pending or completed lock action already exists for example.tld");
@@ -223,7 +227,7 @@ public final class DomainLockUtilsTest {
assertThrows(
IllegalArgumentException.class,
() ->
DomainLockUtils.createRegistryLockRequest(
domainLockUtils.createRegistryLockRequest(
DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock)))
.hasMessageThat()
.isEqualTo("Domain example.tld is already locked");
@@ -235,7 +239,7 @@ public final class DomainLockUtilsTest {
assertThrows(
IllegalArgumentException.class,
() ->
DomainLockUtils.createRegistryUnlockRequest(
domainLockUtils.createRegistryUnlockRequest(
DOMAIN_NAME, "TheRegistrar", false, clock)))
.hasMessageThat()
.isEqualTo("Domain example.tld is already unlocked");
@@ -244,14 +248,14 @@ public final class DomainLockUtilsTest {
@Test
public void testFailure_applyLock_alreadyApplied() {
RegistryLock lock =
DomainLockUtils.createRegistryLockRequest(
domainLockUtils.createRegistryLockRequest(
DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock);
DomainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false, clock);
domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false, clock);
domain = reloadDomain();
assertThat(
assertThrows(
IllegalArgumentException.class,
() -> DomainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false, clock)))
() -> domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false, clock)))
.hasMessageThat()
.isEqualTo("Domain example.tld is already locked");
assertNoDomainChanges();
@@ -260,13 +264,13 @@ public final class DomainLockUtilsTest {
@Test
public void testFailure_applyLock_expired() {
RegistryLock lock =
DomainLockUtils.createRegistryLockRequest(
domainLockUtils.createRegistryLockRequest(
DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock);
clock.advanceBy(Duration.standardDays(1));
assertThat(
assertThrows(
IllegalArgumentException.class,
() -> DomainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), true, clock)))
() -> domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), true, clock)))
.hasMessageThat()
.isEqualTo("The pending lock has expired; please try again");
assertNoDomainChanges();
@@ -275,11 +279,11 @@ public final class DomainLockUtilsTest {
@Test
public void testFailure_applyLock_nonAdmin_applyAdminLock() {
RegistryLock lock =
DomainLockUtils.createRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", null, true, clock);
domainLockUtils.createRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", null, true, clock);
assertThat(
assertThrows(
IllegalArgumentException.class,
() -> DomainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false, clock)))
() -> domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false, clock)))
.hasMessageThat()
.isEqualTo("Non-admin user cannot complete admin lock");
assertNoDomainChanges();
@@ -288,18 +292,18 @@ public final class DomainLockUtilsTest {
@Test
public void testFailure_applyUnlock_alreadyUnlocked() {
RegistryLock lock =
DomainLockUtils.createRegistryLockRequest(
domainLockUtils.createRegistryLockRequest(
DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock);
DomainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false, clock);
domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false, clock);
RegistryLock unlock =
DomainLockUtils.createRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false, clock);
DomainLockUtils.verifyAndApplyUnlock(unlock.getVerificationCode(), false, clock);
domainLockUtils.createRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false, clock);
domainLockUtils.verifyAndApplyUnlock(unlock.getVerificationCode(), false, clock);
assertThat(
assertThrows(
IllegalArgumentException.class,
() ->
DomainLockUtils.verifyAndApplyUnlock(
domainLockUtils.verifyAndApplyUnlock(
unlock.getVerificationCode(), false, clock)))
.hasMessageThat()
.isEqualTo("Domain example.tld is already unlocked");
@@ -309,7 +313,7 @@ public final class DomainLockUtilsTest {
@Test
public void testFailure_applyLock_alreadyLocked() {
RegistryLock lock =
DomainLockUtils.createRegistryLockRequest(
domainLockUtils.createRegistryLockRequest(
DOMAIN_NAME, "TheRegistrar", POC_ID, false, clock);
String verificationCode = lock.getVerificationCode();
// reload to pick up modification times, etc
@@ -318,7 +322,7 @@ public final class DomainLockUtilsTest {
assertThat(
assertThrows(
IllegalArgumentException.class,
() -> DomainLockUtils.verifyAndApplyLock(verificationCode, false, clock)))
() -> domainLockUtils.verifyAndApplyLock(verificationCode, false, clock)))
.hasMessageThat()
.isEqualTo("Domain example.tld is already locked");
@@ -0,0 +1,39 @@
// Copyright 2020 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.tools;
import static com.google.common.truth.Truth.assertThat;
import java.io.File;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.TemporaryFolder;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class DumpGoldenSchemaCommandTest extends CommandTestCase<DumpGoldenSchemaCommand> {
@Rule public TemporaryFolder tmp = new TemporaryFolder();
public DumpGoldenSchemaCommandTest() {}
@Test
public void testSchemaGeneration() throws Exception {
runCommand(
"--output=" + tmp.getRoot() + File.separatorChar + "golden.sql", "--start_postgresql");
assertThat(new File(tmp.getRoot(), "golden.sql").length()).isGreaterThan(1);
}
}
@@ -30,7 +30,9 @@ import google.registry.model.registrar.Registrar.Type;
import google.registry.model.registry.RegistryLockDao;
import google.registry.persistence.transaction.JpaTestRules;
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageRule;
import google.registry.testing.DeterministicStringGenerator;
import google.registry.testing.FakeClock;
import google.registry.util.StringGenerator.Alphabets;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@@ -51,6 +53,8 @@ public class LockDomainCommandTest extends CommandTestCase<LockDomainCommand> {
createTld("tld");
command.registryAdminClientId = "adminreg";
command.clock = new FakeClock();
command.domainLockUtils =
new DomainLockUtils(new DeterministicStringGenerator(Alphabets.BASE_58));
}
@Test
@@ -33,7 +33,9 @@ import google.registry.model.registry.RegistryLockDao;
import google.registry.persistence.transaction.JpaTestRules;
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageRule;
import google.registry.schema.domain.RegistryLock;
import google.registry.testing.DeterministicStringGenerator;
import google.registry.testing.FakeClock;
import google.registry.util.StringGenerator.Alphabets;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;
@@ -54,14 +56,16 @@ public class UnlockDomainCommandTest extends CommandTestCase<UnlockDomainCommand
createTld("tld");
command.registryAdminClientId = "adminreg";
command.clock = new FakeClock();
command.domainLockUtils =
new DomainLockUtils(new DeterministicStringGenerator(Alphabets.BASE_58));
}
private DomainBase persistLockedDomain(String domainName, String registrarId) {
DomainBase domain = persistResource(newDomainBase(domainName));
RegistryLock lock =
DomainLockUtils.createRegistryLockRequest(
command.domainLockUtils.createRegistryLockRequest(
domainName, registrarId, null, true, command.clock);
DomainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), true, command.clock);
command.domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), true, command.clock);
return reloadResource(domain);
}
@@ -32,16 +32,36 @@ import com.google.common.collect.ImmutableSet;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.Registrar.State;
import google.registry.model.registrar.Registrar.Type;
import google.registry.persistence.transaction.JpaTestRules;
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationWithCoverageRule;
import google.registry.schema.registrar.RegistrarDao;
import google.registry.testing.AppEngineRule;
import google.registry.testing.FakeClock;
import google.registry.util.CidrAddressBlock;
import java.util.Optional;
import org.joda.money.CurrencyUnit;
import org.joda.time.DateTime;
import org.junit.Rule;
import org.junit.Test;
/** Unit tests for {@link UpdateRegistrarCommand}. */
public class UpdateRegistrarCommandTest extends CommandTestCase<UpdateRegistrarCommand> {
private final FakeClock fakeClock = new FakeClock();
@Rule
public final JpaIntegrationWithCoverageRule jpaRule =
new JpaTestRules.Builder().withClock(fakeClock).buildIntegrationWithCoverageRule();
@Test
public void testSuccess_alsoUpdateInCloudSql() throws Exception {
assertThat(loadRegistrar("NewRegistrar").verifyPassword("some_password")).isFalse();
RegistrarDao.saveNew(loadRegistrar("NewRegistrar"));
runCommand("--password=some_password", "--force", "NewRegistrar");
assertThat(loadRegistrar("NewRegistrar").verifyPassword("some_password")).isTrue();
assertThat(RegistrarDao.load("NewRegistrar").get().verifyPassword("some_password")).isTrue();
}
@Test
public void testSuccess_password() throws Exception {
assertThat(loadRegistrar("NewRegistrar").verifyPassword("some_password")).isFalse();
@@ -116,20 +116,18 @@ public class UpdateReservedListCommandTest extends
public void testSaveToCloudSql_succeeds() throws Exception {
populateInitialReservedListInDatastore(true);
populateInitialReservedListInCloudSql(true);
runCommandForced(
"--name=xn--q9jyb4c_common-reserved", "--input=" + reservedTermsPath, "--also_cloud_sql");
runCommandForced("--name=xn--q9jyb4c_common-reserved", "--input=" + reservedTermsPath);
verifyXnq9jyb4cInDatastore();
verifyXnq9jyb4cInCloudSql();
}
@Test
public void testSaveToCloudSql_succeedsEvenPreviousListNotExist() throws Exception {
// Note that, during the dual-write phase, we just always save the revered list to
// Cloud SQL (if --also_cloud_sql is set) without checking if there is a list with
// same name. This is to backfill the existing list in Datastore when we update it.
// Note that, during the dual-write phase, we always save the reserved list to Cloud SQL without
// checking if there is a list with same name. This is to backfill the existing list in Cloud
// Datastore when we update it.
populateInitialReservedListInDatastore(true);
runCommandForced(
"--name=xn--q9jyb4c_common-reserved", "--input=" + reservedTermsPath, "--also_cloud_sql");
runCommandForced("--name=xn--q9jyb4c_common-reserved", "--input=" + reservedTermsPath);
verifyXnq9jyb4cInDatastore();
assertThat(ReservedListDao.checkExists("xn--q9jyb4c_common-reserved")).isTrue();
}
@@ -43,7 +43,6 @@ import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import java.util.Map;
import java.util.Optional;
import java.util.UUID;
import org.joda.time.DateTime;
import org.junit.Before;
import org.junit.Rule;
@@ -97,7 +96,7 @@ public final class RegistryLockGetActionTest {
.setRepoId("repoId")
.setDomainName("example.test")
.setRegistrarId("TheRegistrar")
.setVerificationCode(UUID.randomUUID().toString())
.setVerificationCode("123456789ABCDEFGHJKLMNPQRSTUVWXY")
.setRegistrarPocId("johndoe@theregistrar.com")
.setLockCompletionTimestamp(fakeClock.nowUtc())
.build();
@@ -107,7 +106,7 @@ public final class RegistryLockGetActionTest {
.setRepoId("repoId")
.setDomainName("adminexample.test")
.setRegistrarId("TheRegistrar")
.setVerificationCode(UUID.randomUUID().toString())
.setVerificationCode("122222222ABCDEFGHJKLMNPQRSTUVWXY")
.isSuperuser(true)
.setLockCompletionTimestamp(fakeClock.nowUtc())
.build();
@@ -116,7 +115,7 @@ public final class RegistryLockGetActionTest {
.setRepoId("repoId")
.setDomainName("incomplete.test")
.setRegistrarId("TheRegistrar")
.setVerificationCode(UUID.randomUUID().toString())
.setVerificationCode("111111111ABCDEFGHJKLMNPQRSTUVWXY")
.setRegistrarPocId("johndoe@theregistrar.com")
.build();
@@ -126,7 +125,7 @@ public final class RegistryLockGetActionTest {
.setDomainName("unlocked.test")
.setRegistrarId("TheRegistrar")
.setRegistrarPocId("johndoe@theregistrar.com")
.setVerificationCode(UUID.randomUUID().toString())
.setVerificationCode("123456789ABCDEFGHJKLMNPQRSTUUUUU")
.setLockCompletionTimestamp(fakeClock.nowUtc())
.setUnlockRequestTimestamp(fakeClock.nowUtc())
.setUnlockCompletionTimestamp(fakeClock.nowUtc())
@@ -0,0 +1,407 @@
// Copyright 2020 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.registrar;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.model.EppResourceUtils.loadByForeignKey;
import static google.registry.testing.DatastoreHelper.createTld;
import static google.registry.testing.DatastoreHelper.loadRegistrar;
import static google.registry.testing.DatastoreHelper.newDomainBase;
import static google.registry.testing.DatastoreHelper.persistResource;
import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STATUSES;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import com.google.appengine.api.users.User;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSetMultimap;
import google.registry.model.domain.DomainBase;
import google.registry.model.registry.RegistryLockDao;
import google.registry.persistence.transaction.JpaTestRules;
import google.registry.persistence.transaction.JpaTestRules.JpaIntegrationTestRule;
import google.registry.request.JsonActionRunner;
import google.registry.request.JsonResponse;
import google.registry.request.ResponseImpl;
import google.registry.request.auth.AuthLevel;
import google.registry.request.auth.AuthResult;
import google.registry.request.auth.AuthenticatedRegistrarAccessor;
import google.registry.request.auth.AuthenticatedRegistrarAccessor.Role;
import google.registry.request.auth.UserAuthInfo;
import google.registry.schema.domain.RegistryLock;
import google.registry.testing.AppEngineRule;
import google.registry.testing.DeterministicStringGenerator;
import google.registry.testing.FakeClock;
import google.registry.tools.DomainLockUtils;
import google.registry.util.EmailMessage;
import google.registry.util.SendEmailService;
import google.registry.util.StringGenerator.Alphabets;
import java.util.Map;
import java.util.UUID;
import javax.mail.internet.InternetAddress;
import javax.servlet.http.HttpServletResponse;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.junit.MockitoJUnit;
import org.mockito.junit.MockitoRule;
@RunWith(JUnit4.class)
public final class RegistryLockPostActionTest {
private static final String EMAIL_MESSAGE_TEMPLATE =
"Please click the link below to perform the lock \\/ unlock action on domain example.tld. "
+ "Note: this code will expire in one hour.\n\n"
+ "https:\\/\\/localhost\\/registry-lock-verify\\?lockVerificationCode="
+ "[0-9a-zA-Z_\\-]+&isLock=(true|false)";
@Rule public final AppEngineRule appEngineRule = AppEngineRule.builder().withDatastore().build();
@Rule
public final JpaIntegrationTestRule jpaRule =
new JpaTestRules.Builder().buildIntegrationTestRule();
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
private final User userWithoutPermission =
new User("johndoe@theregistrar.com", "gmail.com", "31337");
// Marla Singer has registry lock auth permissions
private final User userWithLockPermission =
new User("Marla.Singer@crr.com", "gmail.com", "31337");
private final FakeClock clock = new FakeClock();
private InternetAddress outgoingAddress;
private DomainBase domain;
private RegistryLockPostAction action;
@Mock SendEmailService emailService;
@Mock HttpServletResponse mockResponse;
@Before
public void setup() throws Exception {
createTld("tld");
domain = persistResource(newDomainBase("example.tld"));
outgoingAddress = new InternetAddress("domain-registry@example.com");
action =
createAction(
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithLockPermission, false)));
}
@Test
public void testSuccess_lock() throws Exception {
Map<String, ?> response = action.handleJsonRequest(lockRequest());
assertSuccess(response, "lock", "Marla.Singer@crr.com");
}
@Test
public void testSuccess_unlock() throws Exception {
RegistryLockDao.save(
createLock().asBuilder().setLockCompletionTimestamp(clock.nowUtc()).build());
persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
Map<String, ?> response = action.handleJsonRequest(unlockRequest());
assertSuccess(response, "unlock", "Marla.Singer@crr.com");
}
@Test
public void testSuccess_unlock_adminUnlockingAdmin() throws Exception {
RegistryLockDao.save(
createLock()
.asBuilder()
.isSuperuser(true)
.setLockCompletionTimestamp(clock.nowUtc())
.build());
persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
action =
createAction(
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithoutPermission, true)));
Map<String, ?> response = action.handleJsonRequest(unlockRequest());
// we should still email the admin user's email address
assertSuccess(response, "unlock", "johndoe@theregistrar.com");
}
@Test
public void testFailure_unlock_noLock() {
persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
Map<String, ?> response = action.handleJsonRequest(unlockRequest());
assertFailureWithMessage(response, "No lock object for domain example.tld");
}
@Test
public void testFailure_unlock_alreadyUnlocked() {
persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
RegistryLockDao.save(
createLock()
.asBuilder()
.setLockCompletionTimestamp(clock.nowUtc())
.setUnlockRequestTimestamp(clock.nowUtc())
.build());
Map<String, ?> response = action.handleJsonRequest(unlockRequest());
assertFailureWithMessage(response, "A pending unlock action already exists for example.tld");
}
@Test
public void testFailure_unlock_nonAdminUnlockingAdmin() {
RegistryLockDao.save(
createLock()
.asBuilder()
.isSuperuser(true)
.setLockCompletionTimestamp(clock.nowUtc())
.build());
persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
Map<String, ?> response = action.handleJsonRequest(unlockRequest());
assertFailureWithMessage(
response, "Non-admin user cannot unlock admin-locked domain example.tld");
}
@Test
public void testSuccess_adminUser() throws Exception {
// Admin user should be able to lock/unlock regardless -- and we use the admin user's email
action =
createAction(
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithoutPermission, true)));
Map<String, ?> response = action.handleJsonRequest(lockRequest());
assertSuccess(response, "lock", "johndoe@theregistrar.com");
}
@Test
public void testSuccess_adminUser_doesNotRequirePassword() throws Exception {
action =
createAction(
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithoutPermission, true)));
Map<String, ?> response =
action.handleJsonRequest(
ImmutableMap.of(
"clientId", "TheRegistrar",
"fullyQualifiedDomainName", "example.tld",
"isLock", true));
assertSuccess(response, "lock", "johndoe@theregistrar.com");
}
@Test
public void testFailure_noInput() {
Map<String, ?> response = action.handleJsonRequest(null);
assertFailureWithMessage(response, "Null JSON");
}
@Test
public void testFailure_noClientId() {
Map<String, ?> response = action.handleJsonRequest(ImmutableMap.of());
assertFailureWithMessage(response, "Missing key for client: clientId");
}
@Test
public void testFailure_emptyClientId() {
Map<String, ?> response = action.handleJsonRequest(ImmutableMap.of("clientId", ""));
assertFailureWithMessage(response, "Missing key for client: clientId");
}
@Test
public void testFailure_noDomainName() {
Map<String, ?> response =
action.handleJsonRequest(
ImmutableMap.of("clientId", "TheRegistrar", "password", "hi", "isLock", true));
assertFailureWithMessage(response, "Missing key for fullyQualifiedDomainName");
}
@Test
public void testFailure_noLockParam() {
Map<String, ?> response =
action.handleJsonRequest(
ImmutableMap.of(
"clientId", "TheRegistrar",
"fullyQualifiedDomainName", "example.tld",
"password", "hi"));
assertFailureWithMessage(response, "Missing key for isLock");
}
@Test
public void testFailure_notAllowedOnRegistrar() {
persistResource(
loadRegistrar("TheRegistrar").asBuilder().setRegistryLockAllowed(false).build());
Map<String, ?> response = action.handleJsonRequest(lockRequest());
assertFailureWithMessage(response, "Registry lock not allowed for this registrar");
}
@Test
public void testFailure_noPassword() {
Map<String, ?> response =
action.handleJsonRequest(
ImmutableMap.of(
"clientId", "TheRegistrar",
"fullyQualifiedDomainName", "example.tld",
"isLock", true));
assertFailureWithMessage(response, "Missing key for password");
}
@Test
public void testFailure_notEnabledForRegistrarContact() {
action =
createAction(
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithoutPermission, false)));
Map<String, ?> response =
action.handleJsonRequest(
ImmutableMap.of(
"clientId", "TheRegistrar",
"fullyQualifiedDomainName", "example.tld",
"isLock", true,
"password", "hi"));
assertFailureWithMessage(response, "Incorrect registry lock password for contact");
}
@Test
public void testFailure_badPassword() {
Map<String, ?> response =
action.handleJsonRequest(
ImmutableMap.of(
"clientId", "TheRegistrar",
"fullyQualifiedDomainName", "example.tld",
"isLock", true,
"password", "badPassword"));
assertFailureWithMessage(response, "Incorrect registry lock password for contact");
}
@Test
public void testFailure_invalidDomain() {
Map<String, ?> response =
action.handleJsonRequest(
ImmutableMap.of(
"clientId", "TheRegistrar",
"fullyQualifiedDomainName", "bad.tld",
"isLock", true,
"password", "hi"));
assertFailureWithMessage(response, "Unknown domain bad.tld");
}
@Test
public void testSuccess_previousLockUnlocked() throws Exception {
RegistryLockDao.save(
createLock()
.asBuilder()
.setLockCompletionTimestamp(clock.nowUtc().minusMinutes(1))
.setUnlockRequestTimestamp(clock.nowUtc().minusMinutes(1))
.setUnlockCompletionTimestamp(clock.nowUtc().minusMinutes(1))
.build());
Map<String, ?> response = action.handleJsonRequest(lockRequest());
assertSuccess(response, "lock", "Marla.Singer@crr.com");
}
@Test
public void testSuccess_previousLockExpired() throws Exception {
RegistryLock previousLock = RegistryLockDao.save(createLock());
previousLock = RegistryLockDao.getByVerificationCode(previousLock.getVerificationCode()).get();
clock.setTo(previousLock.getLockRequestTimestamp().plusHours(2));
Map<String, ?> response = action.handleJsonRequest(lockRequest());
assertSuccess(response, "lock", "Marla.Singer@crr.com");
}
@Test
public void testFailure_alreadyPendingLock() {
RegistryLockDao.save(createLock());
Map<String, ?> response = action.handleJsonRequest(lockRequest());
assertFailureWithMessage(
response, "A pending or completed lock action already exists for example.tld");
}
@Test
public void testFailure_alreadyLocked() {
persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
Map<String, ?> response = action.handleJsonRequest(lockRequest());
assertFailureWithMessage(response, "Domain example.tld is already locked");
}
@Test
public void testFailure_alreadyUnlocked() {
Map<String, ?> response = action.handleJsonRequest(unlockRequest());
assertFailureWithMessage(response, "Domain example.tld is already unlocked");
}
private ImmutableMap<String, Object> lockRequest() {
return fullRequest(true);
}
private ImmutableMap<String, Object> unlockRequest() {
return fullRequest(false);
}
private ImmutableMap<String, Object> fullRequest(boolean lock) {
return ImmutableMap.of(
"isLock", lock,
"clientId", "TheRegistrar",
"fullyQualifiedDomainName", "example.tld",
"password", "hi");
}
private RegistryLock createLock() {
DomainBase domain = loadByForeignKey(DomainBase.class, "example.tld", clock.nowUtc()).get();
return new RegistryLock.Builder()
.setDomainName("example.tld")
.isSuperuser(false)
.setVerificationCode(UUID.randomUUID().toString())
.setRegistrarId("TheRegistrar")
.setRepoId(domain.getRepoId())
.setRegistrarPocId("Marla.Singer@crr.com")
.build();
}
private void assertSuccess(Map<String, ?> response, String lockAction, String recipient)
throws Exception {
assertThat(response)
.containsExactly(
"status", "SUCCESS",
"results", ImmutableList.of(),
"message", String.format("Successful %s", lockAction));
verifyEmail(recipient);
}
private void assertFailureWithMessage(Map<String, ?> response, String message) {
assertThat(response)
.containsExactly("status", "ERROR", "results", ImmutableList.of(), "message", message);
verifyNoMoreInteractions(emailService);
}
private void verifyEmail(String recipient) throws Exception {
ArgumentCaptor<EmailMessage> emailCaptor = ArgumentCaptor.forClass(EmailMessage.class);
verify(emailService).sendEmail(emailCaptor.capture());
EmailMessage sentMessage = emailCaptor.getValue();
assertThat(sentMessage.subject()).matches("Registry (un)?lock verification");
assertThat(sentMessage.body()).matches(EMAIL_MESSAGE_TEMPLATE);
assertThat(sentMessage.from()).isEqualTo(new InternetAddress("domain-registry@example.com"));
assertThat(sentMessage.recipients()).containsExactly(new InternetAddress(recipient));
}
private RegistryLockPostAction createAction(AuthResult authResult) {
AuthenticatedRegistrarAccessor registrarAccessor =
AuthenticatedRegistrarAccessor.createForTesting(
ImmutableSetMultimap.of("TheRegistrar", Role.OWNER, "NewRegistrar", Role.OWNER));
JsonActionRunner jsonActionRunner =
new JsonActionRunner(ImmutableMap.of(), new JsonResponse(new ResponseImpl(mockResponse)));
DomainLockUtils domainLockUtils =
new DomainLockUtils(new DeterministicStringGenerator(Alphabets.BASE_58));
return new RegistryLockPostAction(
jsonActionRunner,
authResult,
registrarAccessor,
emailService,
clock,
domainLockUtils,
outgoingAddress);
}
}
@@ -47,11 +47,14 @@ import google.registry.schema.domain.RegistryLock;
import google.registry.security.XsrfTokenManager;
import google.registry.testing.AppEngineRule;
import google.registry.testing.DatastoreHelper;
import google.registry.testing.DeterministicStringGenerator;
import google.registry.testing.FakeClock;
import google.registry.testing.FakeResponse;
import google.registry.testing.InjectRule;
import google.registry.testing.UserInfo;
import java.util.UUID;
import google.registry.tools.DomainLockUtils;
import google.registry.util.StringGenerator;
import google.registry.util.StringGenerator.Alphabets;
import javax.servlet.http.HttpServletRequest;
import org.joda.time.Duration;
import org.junit.Before;
@@ -81,7 +84,9 @@ public final class RegistryLockVerifyActionTest {
private final HttpServletRequest request = mock(HttpServletRequest.class);
private final UserService userService = UserServiceFactory.getUserService();
private final User user = new User("marla.singer@example.com", "gmail.com", "12345");
private final String lockId = "f1be78a2-2d61-458c-80f0-9dd8f2f8625f";
private final String lockId = "123456789ABCDEFGHJKLMNPQRSTUVWXY";
private final StringGenerator stringGenerator =
new DeterministicStringGenerator(Alphabets.BASE_58);
private FakeResponse response;
private DomainBase domain;
@@ -145,7 +150,7 @@ public final class RegistryLockVerifyActionTest {
@Test
public void testFailure_badVerificationCode() {
RegistryLockDao.save(
createLock().asBuilder().setVerificationCode(UUID.randomUUID().toString()).build());
createLock().asBuilder().setVerificationCode("AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA").build());
action.run();
assertThat(response.getPayload()).contains("Failed: Invalid verification code");
assertNoDomainChanges();
@@ -330,7 +335,8 @@ public final class RegistryLockVerifyActionTest {
private RegistryLockVerifyAction createAction(String lockVerificationCode, Boolean isLock) {
response = new FakeResponse();
RegistryLockVerifyAction action =
new RegistryLockVerifyAction(fakeClock, lockVerificationCode, isLock);
new RegistryLockVerifyAction(
fakeClock, new DomainLockUtils(stringGenerator), lockVerificationCode, isLock);
authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
action.req = request;
action.response = response;
@@ -6,4 +6,5 @@ PATH CLASS METHODS OK AUTH_METHODS
/registrar-ote-status OteStatusAction POST n API,LEGACY USER PUBLIC
/registrar-settings RegistrarSettingsAction POST n API,LEGACY USER PUBLIC
/registry-lock-get RegistryLockGetAction GET n API,LEGACY USER PUBLIC
/registry-lock-post RegistryLockPostAction POST n API,LEGACY USER PUBLIC
/registry-lock-verify RegistryLockVerifyAction GET n API,LEGACY USER PUBLIC
@@ -0,0 +1,31 @@
-- Copyright 2020 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.
create table "RegistrarPoc" (
email_address text not null,
allowed_to_set_registry_lock_password boolean not null,
fax_number text,
gae_user_id text,
name text,
phone_number text,
registry_lock_password_hash text,
registry_lock_password_salt text,
types text[],
visible_in_domain_whois_as_abuse boolean not null,
visible_in_whois_as_admin boolean not null,
visible_in_whois_as_tech boolean not null,
primary key (email_address)
);
create index registrarpoc_gae_user_id_idx on "RegistrarPoc" (gae_user_id);
@@ -0,0 +1,22 @@
-- Copyright 2020 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.
create table "Lock" (
resource_name text not null,
tld text not null,
acquired_time timestamptz not null,
expiration_time timestamptz not null,
request_log_id text not null,
primary key (resource_name, tld)
);
@@ -77,6 +77,15 @@
primary key (id)
);
create table "Lock" (
resource_name text not null,
tld text not null,
acquired_time timestamptz not null,
expiration_time timestamptz not null,
request_log_id text not null,
primary key (resource_name, tld)
);
create table "PremiumEntry" (
revision_id int8 not null,
domain_label text not null,
@@ -142,6 +151,22 @@
primary key (client_id)
);
create table "RegistrarPoc" (
email_address text not null,
allowed_to_set_registry_lock_password boolean not null,
fax_number text,
gae_user_id text,
name text,
phone_number text,
registry_lock_password_hash text,
registry_lock_password_salt text,
types text[],
visible_in_domain_whois_as_abuse boolean not null,
visible_in_whois_as_admin boolean not null,
visible_in_whois_as_tech boolean not null,
primary key (email_address)
);
create table "RegistryLock" (
revision_id bigserial not null,
domain_name text not null,
@@ -181,6 +206,7 @@ create index IDXrwl38wwkli1j7gkvtywi9jokq on "Domain" (tld);
create index premiumlist_name_idx on "PremiumList" (name);
create index registrar_name_idx on "Registrar" (registrar_name);
create index registrar_iana_identifier_idx on "Registrar" (iana_identifier);
create index registrarpoc_gae_user_id_idx on "RegistrarPoc" (gae_user_id);
create index idx_registry_lock_verification_code on "RegistryLock" (verification_code);
create index idx_registry_lock_registrar_id on "RegistryLock" (registrar_id);
@@ -116,6 +116,19 @@ CREATE TABLE public."Domain" (
);
--
-- Name: Lock; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public."Lock" (
resource_name text NOT NULL,
tld text NOT NULL,
acquired_time timestamp with time zone NOT NULL,
expiration_time timestamp with time zone NOT NULL,
request_log_id text NOT NULL
);
--
-- Name: PremiumEntry; Type: TABLE; Schema: public; Owner: -
--
@@ -212,6 +225,26 @@ CREATE TABLE public."Registrar" (
);
--
-- Name: RegistrarPoc; Type: TABLE; Schema: public; Owner: -
--
CREATE TABLE public."RegistrarPoc" (
email_address text NOT NULL,
allowed_to_set_registry_lock_password boolean NOT NULL,
fax_number text,
gae_user_id text,
name text,
phone_number text,
registry_lock_password_hash text,
registry_lock_password_salt text,
types text[],
visible_in_domain_whois_as_abuse boolean NOT NULL,
visible_in_whois_as_admin boolean NOT NULL,
visible_in_whois_as_tech boolean NOT NULL
);
--
-- Name: RegistryLock; Type: TABLE; Schema: public; Owner: -
--
@@ -354,6 +387,14 @@ ALTER TABLE ONLY public."Domain"
ADD CONSTRAINT "Domain_pkey" PRIMARY KEY (repo_id);
--
-- Name: Lock Lock_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."Lock"
ADD CONSTRAINT "Lock_pkey" PRIMARY KEY (resource_name, tld);
--
-- Name: PremiumEntry PremiumEntry_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -370,6 +411,14 @@ ALTER TABLE ONLY public."PremiumList"
ADD CONSTRAINT "PremiumList_pkey" PRIMARY KEY (revision_id);
--
-- Name: RegistrarPoc RegistrarPoc_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
ALTER TABLE ONLY public."RegistrarPoc"
ADD CONSTRAINT "RegistrarPoc_pkey" PRIMARY KEY (email_address);
--
-- Name: Registrar Registrar_pkey; Type: CONSTRAINT; Schema: public; Owner: -
--
@@ -480,6 +529,13 @@ CREATE INDEX registrar_iana_identifier_idx ON public."Registrar" USING btree (ia
CREATE INDEX registrar_name_idx ON public."Registrar" USING btree (registrar_name);
--
-- Name: registrarpoc_gae_user_id_idx; Type: INDEX; Schema: public; Owner: -
--
CREATE INDEX registrarpoc_gae_user_id_idx ON public."RegistrarPoc" USING btree (gae_user_id);
--
-- Name: reservedlist_name_idx; Type: INDEX; Schema: public; Owner: -
--
+1
View File
@@ -115,6 +115,7 @@ spotless {
format 'misc', {
clearSteps()
target '**/*.gradle'
targetExclude '**/cloudbuild-caches/**'
trimTrailingWhitespace()
indentWithSpaces(2)
endWithNewline()
@@ -25,7 +25,7 @@ import com.google.common.collect.ImmutableList;
import dagger.Lazy;
import dagger.Module;
import dagger.Provides;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import google.registry.networking.util.SelfSignedCaCertificate;
import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
@@ -163,9 +163,9 @@ public final class CertificateSupplierModule {
@Singleton
@Provides
static SelfSignedCertificate provideSelfSignedCertificate() {
static SelfSignedCaCertificate provideSelfSignedCertificate() {
try {
return new SelfSignedCertificate();
return SelfSignedCaCertificate.create();
} catch (Exception e) {
throw new RuntimeException(e);
}
@@ -174,7 +174,7 @@ public final class CertificateSupplierModule {
@Singleton
@Provides
@SelfSigned
static Supplier<PrivateKey> provideSelfSignedPrivateKeySupplier(SelfSignedCertificate ssc) {
static Supplier<PrivateKey> provideSelfSignedPrivateKeySupplier(SelfSignedCaCertificate ssc) {
return Suppliers.ofInstance(ssc.key());
}
@@ -182,7 +182,7 @@ public final class CertificateSupplierModule {
@Provides
@SelfSigned
static Supplier<ImmutableList<X509Certificate>> provideSelfSignedCertificatesSupplier(
SelfSignedCertificate ssc) {
SelfSignedCaCertificate ssc) {
return Suppliers.ofInstance(ImmutableList.of(ssc.cert()));
}
@@ -0,0 +1,112 @@
// Copyright 2020 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.networking.util;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.PrivateKey;
import java.security.SecureRandom;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
import java.util.Date;
import java.util.Random;
import org.bouncycastle.asn1.ASN1ObjectIdentifier;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.BasicConstraints;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
/** A self-signed certificate authority (CA) cert for use in tests. */
// TODO(weiminyu): make this class test-only. Requires refactor in proxy and prober.
public class SelfSignedCaCertificate {
private static final String DEFAULT_ISSUER_FQDN = "registry-test";
private static final Date DEFAULT_NOT_BEFORE =
Date.from(Instant.now().minus(Duration.ofHours(1)));
private static final Date DEFAULT_NOT_AFTER = Date.from(Instant.now().plus(Duration.ofDays(1)));
private static final Random RANDOM = new Random();
private static final BouncyCastleProvider PROVIDER = new BouncyCastleProvider();
private static final KeyPairGenerator keyGen = createKeyPairGenerator();
private final PrivateKey privateKey;
private final X509Certificate cert;
public SelfSignedCaCertificate(PrivateKey privateKey, X509Certificate cert) {
this.privateKey = privateKey;
this.cert = cert;
}
public PrivateKey key() {
return privateKey;
}
public X509Certificate cert() {
return cert;
}
public static SelfSignedCaCertificate create() throws Exception {
return create(
keyGen.generateKeyPair(), DEFAULT_ISSUER_FQDN, DEFAULT_NOT_BEFORE, DEFAULT_NOT_AFTER);
}
public static SelfSignedCaCertificate create(String fqdn) throws Exception {
return create(fqdn, DEFAULT_NOT_BEFORE, DEFAULT_NOT_AFTER);
}
public static SelfSignedCaCertificate create(String fqdn, Date from, Date to) throws Exception {
return create(keyGen.generateKeyPair(), fqdn, from, to);
}
public static SelfSignedCaCertificate create(KeyPair keyPair, String fqdn, Date from, Date to)
throws Exception {
return new SelfSignedCaCertificate(keyPair.getPrivate(), createCaCert(keyPair, fqdn, from, to));
}
static KeyPairGenerator createKeyPairGenerator() {
try {
KeyPairGenerator keyGen = KeyPairGenerator.getInstance("RSA", PROVIDER);
keyGen.initialize(2048, new SecureRandom());
return keyGen;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
/** Returns a self-signed Certificate Authority (CA) certificate. */
static X509Certificate createCaCert(KeyPair keyPair, String fqdn, Date from, Date to)
throws Exception {
X500Name owner = new X500Name("CN=" + fqdn);
ContentSigner signer =
new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(keyPair.getPrivate());
X509v3CertificateBuilder builder =
new JcaX509v3CertificateBuilder(
owner, new BigInteger(64, RANDOM), from, to, owner, keyPair.getPublic());
// Mark cert as CA by adding basicConstraint with cA=true to the builder
BasicConstraints basicConstraints = new BasicConstraints(true);
builder.addExtension(new ASN1ObjectIdentifier("2.5.29.19"), true, basicConstraints);
X509CertificateHolder certHolder = builder.build(signer);
return new JcaX509CertificateConverter().setProvider(PROVIDER).getCertificate(certHolder);
}
}
@@ -21,6 +21,7 @@ import static google.registry.networking.handler.SslInitializerTestUtils.signKey
import static google.registry.networking.handler.SslInitializerTestUtils.verifySslExcpetion;
import com.google.common.collect.ImmutableList;
import google.registry.networking.util.SelfSignedCaCertificate;
import io.netty.channel.Channel;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelPipeline;
@@ -35,7 +36,6 @@ import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.util.InsecureTrustManagerFactory;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.cert.CertPathBuilderException;
@@ -153,7 +153,7 @@ public class SslClientInitializerTest {
@Test
public void testFailure_defaultTrustManager_rejectSelfSignedCert() throws Exception {
SelfSignedCertificate ssc = new SelfSignedCertificate(SSL_HOST);
SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create(SSL_HOST);
LocalAddress localAddress =
new LocalAddress("DEFAULT_TRUST_MANAGER_REJECT_SELF_SIGNED_CERT_" + sslProvider);
nettyRule.setUpServer(localAddress, getServerHandler(false, ssc.key(), ssc.cert()));
@@ -177,7 +177,7 @@ public class SslClientInitializerTest {
KeyPair keyPair = getKeyPair();
// Generate a self signed certificate, and use it to sign the key pair.
SelfSignedCertificate ssc = new SelfSignedCertificate();
SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create();
X509Certificate cert = signKeyPair(ssc, keyPair, SSL_HOST);
// Set up the server to use the signed cert and private key to perform handshake;
@@ -206,7 +206,7 @@ public class SslClientInitializerTest {
KeyPair keyPair = getKeyPair();
// Generate a self signed certificate, and use it to sign the key pair.
SelfSignedCertificate ssc = new SelfSignedCertificate();
SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create();
X509Certificate cert =
signKeyPair(
ssc,
@@ -240,7 +240,7 @@ public class SslClientInitializerTest {
KeyPair keyPair = getKeyPair();
// Generate a self signed certificate, and use it to sign the key pair.
SelfSignedCertificate ssc = new SelfSignedCertificate();
SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create();
X509Certificate cert =
signKeyPair(
ssc,
@@ -272,8 +272,8 @@ public class SslClientInitializerTest {
new LocalAddress(
"CUSTOM_TRUST_MANAGER_ACCEPT_SELF_SIGNED_CERT_CLIENT_CERT_REQUIRED_" + sslProvider);
SelfSignedCertificate serverSsc = new SelfSignedCertificate(SSL_HOST);
SelfSignedCertificate clientSsc = new SelfSignedCertificate();
SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST);
SelfSignedCaCertificate clientSsc = SelfSignedCaCertificate.create();
// Set up the server to require client certificate.
nettyRule.setUpServer(localAddress, getServerHandler(true, serverSsc.key(), serverSsc.cert()));
@@ -311,7 +311,7 @@ public class SslClientInitializerTest {
KeyPair keyPair = getKeyPair();
// Generate a self signed certificate, and use it to sign the key pair.
SelfSignedCertificate ssc = new SelfSignedCertificate();
SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create();
X509Certificate cert = signKeyPair(ssc, keyPair, "wrong.com");
// Set up the server to use the signed cert and private key to perform handshake;
@@ -18,15 +18,14 @@ import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import com.google.common.base.Throwables;
import google.registry.networking.util.SelfSignedCaCertificate;
import io.netty.channel.Channel;
import io.netty.channel.ChannelFuture;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import java.math.BigInteger;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.SecureRandom;
import java.security.Security;
import java.security.cert.X509Certificate;
import java.time.Duration;
import java.time.Instant;
@@ -34,17 +33,13 @@ import java.util.Date;
import java.util.concurrent.ExecutionException;
import javax.net.ssl.SSLSession;
import org.bouncycastle.asn1.x500.X500Name;
import org.bouncycastle.asn1.x509.AlgorithmIdentifier;
import org.bouncycastle.asn1.x509.SubjectPublicKeyInfo;
import org.bouncycastle.cert.X509CertificateHolder;
import org.bouncycastle.cert.X509v3CertificateBuilder;
import org.bouncycastle.cert.jcajce.JcaX509CertificateConverter;
import org.bouncycastle.crypto.util.PrivateKeyFactory;
import org.bouncycastle.cert.jcajce.JcaX509v3CertificateBuilder;
import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.operator.ContentSigner;
import org.bouncycastle.operator.DefaultDigestAlgorithmIdentifierFinder;
import org.bouncycastle.operator.DefaultSignatureAlgorithmIdentifierFinder;
import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;
import org.bouncycastle.operator.jcajce.JcaContentSignerBuilder;
/**
* Utility class that provides methods used by {@link SslClientInitializerTest} and {@link
@@ -52,16 +47,23 @@ import org.bouncycastle.operator.bc.BcRSAContentSignerBuilder;
*/
public final class SslInitializerTestUtils {
static {
Security.addProvider(new BouncyCastleProvider());
}
private static final BouncyCastleProvider PROVIDER = new BouncyCastleProvider();
private static final KeyPairGenerator KEY_PAIR_GENERATOR = getKeyPairGenerator();
private SslInitializerTestUtils() {}
private static KeyPairGenerator getKeyPairGenerator() {
try {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", PROVIDER);
keyPairGenerator.initialize(2048, new SecureRandom());
return keyPairGenerator;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static KeyPair getKeyPair() throws Exception {
KeyPairGenerator keyPairGenerator = KeyPairGenerator.getInstance("RSA", "BC");
keyPairGenerator.initialize(2048, new SecureRandom());
return keyPairGenerator.generateKeyPair();
return KEY_PAIR_GENERATOR.generateKeyPair();
}
/**
@@ -71,26 +73,20 @@ public final class SslInitializerTestUtils {
* @return signed public key (of the key pair) certificate
*/
public static X509Certificate signKeyPair(
SelfSignedCertificate ssc, KeyPair keyPair, String hostname, Date from, Date to)
SelfSignedCaCertificate ssc, KeyPair keyPair, String hostname, Date from, Date to)
throws Exception {
X500Name subjectDnName = new X500Name("CN=" + hostname);
BigInteger serialNumber = BigInteger.valueOf(System.currentTimeMillis());
X500Name issuerDnName = new X500Name(ssc.cert().getIssuerDN().getName());
SubjectPublicKeyInfo subPubKeyInfo =
SubjectPublicKeyInfo.getInstance(keyPair.getPublic().getEncoded());
AlgorithmIdentifier sigAlgId =
new DefaultSignatureAlgorithmIdentifierFinder().find("SHA256WithRSAEncryption");
AlgorithmIdentifier digAlgId = new DefaultDigestAlgorithmIdentifierFinder().find(sigAlgId);
ContentSigner sigGen =
new BcRSAContentSignerBuilder(sigAlgId, digAlgId)
.build(PrivateKeyFactory.createKey(ssc.key().getEncoded()));
ContentSigner sigGen = new JcaContentSignerBuilder("SHA256WithRSAEncryption").build(ssc.key());
X509v3CertificateBuilder v3CertGen =
new X509v3CertificateBuilder(
issuerDnName, serialNumber, from, to, subjectDnName, subPubKeyInfo);
new JcaX509v3CertificateBuilder(
issuerDnName, serialNumber, from, to, subjectDnName, keyPair.getPublic());
X509CertificateHolder certificateHolder = v3CertGen.build(sigGen);
return new JcaX509CertificateConverter().setProvider("BC").getCertificate(certificateHolder);
return new JcaX509CertificateConverter()
.setProvider(PROVIDER)
.getCertificate(certificateHolder);
}
/**
@@ -100,7 +96,7 @@ public final class SslInitializerTestUtils {
* @return signed public key (of the key pair) certificate
*/
public static X509Certificate signKeyPair(
SelfSignedCertificate ssc, KeyPair keyPair, String hostname) throws Exception {
SelfSignedCaCertificate ssc, KeyPair keyPair, String hostname) throws Exception {
return signKeyPair(
ssc,
keyPair,
@@ -23,6 +23,7 @@ import static google.registry.networking.handler.SslServerInitializer.CLIENT_CER
import com.google.common.base.Suppliers;
import com.google.common.collect.ImmutableList;
import google.registry.networking.util.SelfSignedCaCertificate;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelInitializer;
import io.netty.channel.ChannelPipeline;
@@ -33,7 +34,6 @@ import io.netty.handler.ssl.OpenSsl;
import io.netty.handler.ssl.SslContextBuilder;
import io.netty.handler.ssl.SslHandler;
import io.netty.handler.ssl.SslProvider;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.cert.CertificateException;
@@ -127,7 +127,7 @@ public class SslServerInitializerTest {
@Test
public void testSuccess_swappedInitializerWithSslHandler() throws Exception {
SelfSignedCertificate ssc = new SelfSignedCertificate(SSL_HOST);
SelfSignedCaCertificate ssc = SelfSignedCaCertificate.create(SSL_HOST);
SslServerInitializer<EmbeddedChannel> sslServerInitializer =
new SslServerInitializer<>(
true,
@@ -147,12 +147,12 @@ public class SslServerInitializerTest {
@Test
public void testSuccess_trustAnyClientCert() throws Exception {
SelfSignedCertificate serverSsc = new SelfSignedCertificate(SSL_HOST);
SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST);
LocalAddress localAddress = new LocalAddress("TRUST_ANY_CLIENT_CERT_" + sslProvider);
nettyRule.setUpServer(
localAddress, getServerHandler(true, false, serverSsc.key(), serverSsc.cert()));
SelfSignedCertificate clientSsc = new SelfSignedCertificate();
SelfSignedCaCertificate clientSsc = SelfSignedCaCertificate.create();
nettyRule.setUpClient(
localAddress, getClientHandler(serverSsc.cert(), clientSsc.key(), clientSsc.cert()));
@@ -168,13 +168,13 @@ public class SslServerInitializerTest {
@Test
public void testFailure_clientCertExpired() throws Exception {
SelfSignedCertificate serverSsc = new SelfSignedCertificate(SSL_HOST);
SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST);
LocalAddress localAddress = new LocalAddress("CLIENT_CERT_EXPIRED_" + sslProvider);
nettyRule.setUpServer(
localAddress, getServerHandler(true, true, serverSsc.key(), serverSsc.cert()));
SelfSignedCertificate clientSsc =
new SelfSignedCertificate(
SelfSignedCaCertificate clientSsc =
SelfSignedCaCertificate.create(
"CLIENT",
Date.from(Instant.now().minus(Duration.ofDays(2))),
Date.from(Instant.now().minus(Duration.ofDays(1))));
@@ -189,13 +189,13 @@ public class SslServerInitializerTest {
@Test
public void testFailure_clientCertNotYetValid() throws Exception {
SelfSignedCertificate serverSsc = new SelfSignedCertificate(SSL_HOST);
SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST);
LocalAddress localAddress = new LocalAddress("CLIENT_CERT_EXPIRED_" + sslProvider);
nettyRule.setUpServer(
localAddress, getServerHandler(true, true, serverSsc.key(), serverSsc.cert()));
SelfSignedCertificate clientSsc =
new SelfSignedCertificate(
SelfSignedCaCertificate clientSsc =
SelfSignedCaCertificate.create(
"CLIENT",
Date.from(Instant.now().plus(Duration.ofDays(1))),
Date.from(Instant.now().plus(Duration.ofDays(2))));
@@ -210,7 +210,7 @@ public class SslServerInitializerTest {
@Test
public void testSuccess_doesNotRequireClientCert() throws Exception {
SelfSignedCertificate serverSsc = new SelfSignedCertificate(SSL_HOST);
SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST);
LocalAddress localAddress = new LocalAddress("DOES_NOT_REQUIRE_CLIENT_CERT_" + sslProvider);
nettyRule.setUpServer(
@@ -230,7 +230,7 @@ public class SslServerInitializerTest {
@Test
public void testSuccess_CertSignedByOtherCA() throws Exception {
// The self-signed cert of the CA.
SelfSignedCertificate caSsc = new SelfSignedCertificate();
SelfSignedCaCertificate caSsc = SelfSignedCaCertificate.create();
KeyPair keyPair = getKeyPair();
X509Certificate serverCert = signKeyPair(caSsc, keyPair, SSL_HOST);
LocalAddress localAddress = new LocalAddress("CERT_SIGNED_BY_OTHER_CA_" + sslProvider);
@@ -244,7 +244,7 @@ public class SslServerInitializerTest {
// Serving both the server cert, and the CA cert
serverCert,
caSsc.cert()));
SelfSignedCertificate clientSsc = new SelfSignedCertificate();
SelfSignedCaCertificate clientSsc = SelfSignedCaCertificate.create();
nettyRule.setUpClient(
localAddress,
getClientHandler(
@@ -263,7 +263,7 @@ public class SslServerInitializerTest {
@Test
public void testFailure_requireClientCertificate() throws Exception {
SelfSignedCertificate serverSsc = new SelfSignedCertificate(SSL_HOST);
SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create(SSL_HOST);
LocalAddress localAddress = new LocalAddress("REQUIRE_CLIENT_CERT_" + sslProvider);
nettyRule.setUpServer(
@@ -285,12 +285,12 @@ public class SslServerInitializerTest {
@Test
public void testFailure_wrongHostnameInCertificate() throws Exception {
SelfSignedCertificate serverSsc = new SelfSignedCertificate("wrong.com");
SelfSignedCaCertificate serverSsc = SelfSignedCaCertificate.create("wrong.com");
LocalAddress localAddress = new LocalAddress("WRONG_HOSTNAME_" + sslProvider);
nettyRule.setUpServer(
localAddress, getServerHandler(true, false, serverSsc.key(), serverSsc.cert()));
SelfSignedCertificate clientSsc = new SelfSignedCertificate();
SelfSignedCaCertificate clientSsc = SelfSignedCaCertificate.create();
nettyRule.setUpClient(
localAddress, getClientHandler(serverSsc.cert(), clientSsc.key(), clientSsc.cert()));
@@ -26,7 +26,7 @@ import dagger.Component;
import dagger.Module;
import dagger.Provides;
import google.registry.networking.module.CertificateSupplierModule.Mode;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import google.registry.networking.util.SelfSignedCaCertificate;
import java.io.ByteArrayOutputStream;
import java.io.OutputStreamWriter;
import java.security.KeyPair;
@@ -47,7 +47,7 @@ import org.junit.runners.JUnit4;
@RunWith(JUnit4.class)
public class CertificateSupplierModuleTest {
private SelfSignedCertificate ssc;
private SelfSignedCaCertificate ssc;
private PrivateKey key;
private Certificate cert;
private TestComponent component;
@@ -62,7 +62,7 @@ public class CertificateSupplierModuleTest {
@Before
public void setUp() throws Exception {
ssc = new SelfSignedCertificate();
ssc = SelfSignedCaCertificate.create();
KeyPair keyPair = getKeyPair();
key = keyPair.getPrivate();
cert = signKeyPair(ssc, keyPair, "example.tld");
@@ -23,6 +23,7 @@ import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.Assert.assertThrows;
import com.google.common.base.Throwables;
import google.registry.networking.util.SelfSignedCaCertificate;
import google.registry.proxy.handler.HttpsRelayServiceHandler.NonOkHttpResponseException;
import google.registry.testing.FakeClock;
import io.netty.buffer.ByteBuf;
@@ -34,7 +35,6 @@ import io.netty.handler.codec.http.FullHttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.codec.http.cookie.DefaultCookie;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.util.concurrent.Promise;
import java.security.cert.X509Certificate;
import org.junit.Before;
@@ -123,7 +123,7 @@ public class EppProtocolModuleTest extends ProtocolModuleTest {
@Before
public void setUp() throws Exception {
testComponent = makeTestComponent(new FakeClock());
certificate = new SelfSignedCertificate().cert();
certificate = SelfSignedCaCertificate.create().cert();
initializeChannel(
ch -> {
ch.attr(REMOTE_ADDRESS_KEY).set(CLIENT_ADDRESS);
@@ -27,6 +27,7 @@ import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.verifyNoMoreInteractions;
import com.google.common.base.Throwables;
import google.registry.networking.util.SelfSignedCaCertificate;
import google.registry.proxy.TestUtils;
import google.registry.proxy.handler.HttpsRelayServiceHandler.NonOkHttpResponseException;
import google.registry.proxy.metric.FrontendMetrics;
@@ -41,7 +42,6 @@ import io.netty.handler.codec.http.HttpResponse;
import io.netty.handler.codec.http.HttpResponseStatus;
import io.netty.handler.codec.http.cookie.Cookie;
import io.netty.handler.codec.http.cookie.DefaultCookie;
import io.netty.handler.ssl.util.SelfSignedCertificate;
import io.netty.util.concurrent.Promise;
import java.security.cert.X509Certificate;
import org.junit.Before;
@@ -114,7 +114,7 @@ public class EppServiceHandlerTest {
@Before
public void setUp() throws Exception {
clientCertificate = new SelfSignedCertificate().cert();
clientCertificate = SelfSignedCaCertificate.create().cert();
channel = setUpNewChannel(eppServiceHandler);
}
@@ -179,7 +179,7 @@ public class EppServiceHandlerTest {
HELLO.getBytes(UTF_8),
metrics);
EmbeddedChannel channel2 = setUpNewChannel(eppServiceHandler2);
X509Certificate clientCertificate2 = new SelfSignedCertificate().cert();
X509Certificate clientCertificate2 = SelfSignedCaCertificate.create().cert();
setHandshakeSuccess(channel2, clientCertificate2);
String certHash2 = getCertificateHash(clientCertificate2);
+13 -5
View File
@@ -27,15 +27,23 @@ fi
environment="$1"
dest="$2"
gcs_prefix="storage.googleapis.com/domain-registry-maven-repository"
gcs_prefix="gcs://domain-registry-maven-repository"
# Let Gradle put its caches (dependency cache and build cache) in the source
# tree. This allows sharing of the caches between steps in a Cloud Build
# task. (See ./cloudbuild-nomulus.yaml, which calls this script in several
# steps). If left at their default location, the caches will be lost after
# each step.
# Note: must be consistent with value in ./cloudbuild-nomulus.yaml
export GRADLE_USER_HOME="./cloudbuild-caches"
if [ "${environment}" == tool ]
then
mkdir -p "${dest}"
./gradlew clean :core:buildToolImage \
-PmavenUrl=https://"${gcs_prefix}"/maven \
-PpluginsUrl=https://"${gcs_prefix}"/plugins
-PmavenUrl="${gcs_prefix}"/maven \
-PpluginsUrl="${gcs_prefix}"/plugins
mv core/build/libs/nomulus.jar "${dest}"
else
@@ -43,8 +51,8 @@ else
mkdir -p "${dest}"
./gradlew clean stage -Penvironment="${environment}" \
-PmavenUrl=https://"${gcs_prefix}"/maven \
-PpluginsUrl=https://"${gcs_prefix}"/plugins
-PmavenUrl="${gcs_prefix}"/maven \
-PpluginsUrl="${gcs_prefix}"/plugins
for service in default pubapi backend tools
do

Some files were not shown because too many files have changed in this diff Show More