mirror of
https://github.com/google/nomulus
synced 2026-08-08 16:26:07 +00:00
Compare commits
7
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d01f1f7604 | ||
|
|
e9610636e4 | ||
|
|
d09fc7ee05 | ||
|
|
0545375eba | ||
|
|
8a045aedd0 | ||
|
|
560bec1e83 | ||
|
|
3e7ea75b6f |
@@ -1,8 +1,8 @@
|
||||
# Nomulus
|
||||
|
||||
| Internal Build | FOSS Build | LGTM | License | Code Search |
|
||||
|----------------|------------|------|---------|-------------|
|
||||
|[](https://storage.googleapis.com/domain-registry-kokoro/internal/index.html)|[](https://storage.googleapis.com/domain-registry-kokoro/foss/index.html)|[](https://lgtm.com/projects/g/google/nomulus/alerts/)|[](https://github.com/google/nomulus/blob/master/LICENSE)|[](https://sourcegraph.com/github.com/google/nomulus)|
|
||||
|:--------------:|:----------:|:----:|:-------:|:-----------:|
|
||||
|[](https://storage.googleapis.com/domain-registry-kokoro/internal/index.html)|[](https://storage.googleapis.com/domain-registry-kokoro/foss/index.html)|[](https://lgtm.com/projects/g/google/nomulus/alerts/)|[](https://github.com/google/nomulus/blob/master/LICENSE)|[](https://cs.opensource.google/nomulus/nomulus)|
|
||||
|
||||

|
||||
|
||||
|
||||
+2
-1
@@ -197,7 +197,8 @@ dependencies {
|
||||
compile deps['com.google.appengine:appengine-remote-api']
|
||||
compile deps['com.google.auth:google-auth-library-credentials']
|
||||
compile deps['com.google.auth:google-auth-library-oauth2-http']
|
||||
runtimeOnly deps['com.google.cloud.sql:postgres-socket-factory']
|
||||
compile deps['com.google.cloud.sql:jdbc-socket-factory-core']
|
||||
compile deps['com.google.cloud.sql:postgres-socket-factory']
|
||||
compile deps['com.google.code.gson:gson']
|
||||
compile deps['com.google.auto.value:auto-value-annotations']
|
||||
compile deps['com.google.code.findbugs:jsr305']
|
||||
|
||||
@@ -10,6 +10,14 @@ 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.github.jnr:jffi:1.2.17
|
||||
com.github.jnr:jnr-a64asm:1.0.0
|
||||
com.github.jnr:jnr-constants:0.9.11
|
||||
com.github.jnr:jnr-enxio:0.19
|
||||
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-jackson2:1.27.0
|
||||
com.google.api-client:google-api-client-java6:1.27.0
|
||||
@@ -50,6 +58,7 @@ com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
|
||||
com.google.apis:google-api-services-monitoring:v3-rev426-1.23.0
|
||||
com.google.apis:google-api-services-pubsub:v1-rev20181105-1.27.0
|
||||
com.google.apis:google-api-services-sheets:v4-rev483-1.22.0
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev56-1.23.0
|
||||
com.google.apis:google-api-services-storage:v1-rev20181109-1.27.0
|
||||
com.google.appengine.tools:appengine-gcs-client:0.6
|
||||
com.google.appengine.tools:appengine-mapreduce:0.9
|
||||
@@ -65,6 +74,8 @@ com.google.cloud.bigdataoss:gcsio:1.9.16
|
||||
com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
@@ -212,11 +223,11 @@ org.mockito:mockito-core:1.9.5
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
org.objenesis:objenesis:1.2
|
||||
org.ow2.asm:asm-analysis:6.0
|
||||
org.ow2.asm:asm-analysis:7.0
|
||||
org.ow2.asm:asm-commons:6.0
|
||||
org.ow2.asm:asm-tree:6.0
|
||||
org.ow2.asm:asm-util:6.0
|
||||
org.ow2.asm:asm:6.0
|
||||
org.ow2.asm:asm-tree:7.0
|
||||
org.ow2.asm:asm-util:7.0
|
||||
org.ow2.asm:asm:7.0
|
||||
org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
org.rnorth:tcp-unix-socket-proxy:1.0.2
|
||||
|
||||
@@ -10,6 +10,14 @@ 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.github.jnr:jffi:1.2.17
|
||||
com.github.jnr:jnr-a64asm:1.0.0
|
||||
com.github.jnr:jnr-constants:0.9.11
|
||||
com.github.jnr:jnr-enxio:0.19
|
||||
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-jackson2:1.27.0
|
||||
com.google.api-client:google-api-client-java6:1.27.0
|
||||
@@ -50,6 +58,7 @@ com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
|
||||
com.google.apis:google-api-services-monitoring:v3-rev426-1.23.0
|
||||
com.google.apis:google-api-services-pubsub:v1-rev20181105-1.27.0
|
||||
com.google.apis:google-api-services-sheets:v4-rev483-1.22.0
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev56-1.23.0
|
||||
com.google.apis:google-api-services-storage:v1-rev20181109-1.27.0
|
||||
com.google.appengine.tools:appengine-gcs-client:0.6
|
||||
com.google.appengine.tools:appengine-mapreduce:0.9
|
||||
@@ -65,6 +74,8 @@ com.google.cloud.bigdataoss:gcsio:1.9.16
|
||||
com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
@@ -207,11 +218,11 @@ org.jvnet.staxex:stax-ex:1.8
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
org.objenesis:objenesis:1.2
|
||||
org.ow2.asm:asm-analysis:6.0
|
||||
org.ow2.asm:asm-analysis:7.0
|
||||
org.ow2.asm:asm-commons:6.0
|
||||
org.ow2.asm:asm-tree:6.0
|
||||
org.ow2.asm:asm-util:6.0
|
||||
org.ow2.asm:asm:6.0
|
||||
org.ow2.asm:asm-tree:7.0
|
||||
org.ow2.asm:asm-util:7.0
|
||||
org.ow2.asm:asm:7.0
|
||||
org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
org.rnorth:tcp-unix-socket-proxy:1.0.2
|
||||
|
||||
@@ -10,6 +10,14 @@ 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.github.jnr:jffi:1.2.17
|
||||
com.github.jnr:jnr-a64asm:1.0.0
|
||||
com.github.jnr:jnr-constants:0.9.11
|
||||
com.github.jnr:jnr-enxio:0.19
|
||||
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-jackson2:1.27.0
|
||||
com.google.api-client:google-api-client-java6:1.27.0
|
||||
@@ -50,6 +58,7 @@ com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
|
||||
com.google.apis:google-api-services-monitoring:v3-rev426-1.23.0
|
||||
com.google.apis:google-api-services-pubsub:v1-rev20181105-1.27.0
|
||||
com.google.apis:google-api-services-sheets:v4-rev483-1.22.0
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev56-1.23.0
|
||||
com.google.apis:google-api-services-storage:v1-rev20181109-1.27.0
|
||||
com.google.appengine.tools:appengine-gcs-client:0.6
|
||||
com.google.appengine.tools:appengine-mapreduce:0.9
|
||||
@@ -65,6 +74,8 @@ com.google.cloud.bigdataoss:gcsio:1.9.16
|
||||
com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
@@ -212,11 +223,11 @@ org.mockito:mockito-core:1.9.5
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
org.objenesis:objenesis:1.2
|
||||
org.ow2.asm:asm-analysis:6.0
|
||||
org.ow2.asm:asm-analysis:7.0
|
||||
org.ow2.asm:asm-commons:6.0
|
||||
org.ow2.asm:asm-tree:6.0
|
||||
org.ow2.asm:asm-util:6.0
|
||||
org.ow2.asm:asm:6.0
|
||||
org.ow2.asm:asm-tree:7.0
|
||||
org.ow2.asm:asm-util:7.0
|
||||
org.ow2.asm:asm:7.0
|
||||
org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
org.rnorth:tcp-unix-socket-proxy:1.0.2
|
||||
|
||||
@@ -10,6 +10,14 @@ 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.github.jnr:jffi:1.2.17
|
||||
com.github.jnr:jnr-a64asm:1.0.0
|
||||
com.github.jnr:jnr-constants:0.9.11
|
||||
com.github.jnr:jnr-enxio:0.19
|
||||
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-jackson2:1.27.0
|
||||
com.google.api-client:google-api-client-java6:1.27.0
|
||||
@@ -50,6 +58,7 @@ com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
|
||||
com.google.apis:google-api-services-monitoring:v3-rev426-1.23.0
|
||||
com.google.apis:google-api-services-pubsub:v1-rev20181105-1.27.0
|
||||
com.google.apis:google-api-services-sheets:v4-rev483-1.22.0
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev56-1.23.0
|
||||
com.google.apis:google-api-services-storage:v1-rev20181109-1.27.0
|
||||
com.google.appengine.tools:appengine-gcs-client:0.6
|
||||
com.google.appengine.tools:appengine-mapreduce:0.9
|
||||
@@ -65,6 +74,8 @@ com.google.cloud.bigdataoss:gcsio:1.9.16
|
||||
com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
@@ -210,11 +221,11 @@ org.mockito:mockito-core:1.9.5
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
org.objenesis:objenesis:1.2
|
||||
org.ow2.asm:asm-analysis:6.0
|
||||
org.ow2.asm:asm-analysis:7.0
|
||||
org.ow2.asm:asm-commons:6.0
|
||||
org.ow2.asm:asm-tree:6.0
|
||||
org.ow2.asm:asm-util:6.0
|
||||
org.ow2.asm:asm:6.0
|
||||
org.ow2.asm:asm-tree:7.0
|
||||
org.ow2.asm:asm-util:7.0
|
||||
org.ow2.asm:asm:7.0
|
||||
org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
org.rnorth:tcp-unix-socket-proxy:1.0.2
|
||||
|
||||
@@ -10,6 +10,14 @@ 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.github.jnr:jffi:1.2.17
|
||||
com.github.jnr:jnr-a64asm:1.0.0
|
||||
com.github.jnr:jnr-constants:0.9.11
|
||||
com.github.jnr:jnr-enxio:0.19
|
||||
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-jackson2:1.27.0
|
||||
com.google.api-client:google-api-client-java6:1.27.0
|
||||
@@ -50,6 +58,7 @@ com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
|
||||
com.google.apis:google-api-services-monitoring:v3-rev426-1.23.0
|
||||
com.google.apis:google-api-services-pubsub:v1-rev20181105-1.27.0
|
||||
com.google.apis:google-api-services-sheets:v4-rev483-1.22.0
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev56-1.23.0
|
||||
com.google.apis:google-api-services-storage:v1-rev20181109-1.27.0
|
||||
com.google.appengine.tools:appengine-gcs-client:0.6
|
||||
com.google.appengine.tools:appengine-mapreduce:0.9
|
||||
@@ -65,6 +74,8 @@ com.google.cloud.bigdataoss:gcsio:1.9.16
|
||||
com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
@@ -212,11 +223,11 @@ org.mockito:mockito-core:1.9.5
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
org.objenesis:objenesis:1.2
|
||||
org.ow2.asm:asm-analysis:6.0
|
||||
org.ow2.asm:asm-analysis:7.0
|
||||
org.ow2.asm:asm-commons:6.0
|
||||
org.ow2.asm:asm-tree:6.0
|
||||
org.ow2.asm:asm-util:6.0
|
||||
org.ow2.asm:asm:6.0
|
||||
org.ow2.asm:asm-tree:7.0
|
||||
org.ow2.asm:asm-util:7.0
|
||||
org.ow2.asm:asm:7.0
|
||||
org.postgresql:postgresql:42.2.6
|
||||
org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
|
||||
@@ -10,6 +10,14 @@ 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.github.jnr:jffi:1.2.17
|
||||
com.github.jnr:jnr-a64asm:1.0.0
|
||||
com.github.jnr:jnr-constants:0.9.11
|
||||
com.github.jnr:jnr-enxio:0.19
|
||||
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-jackson2:1.27.0
|
||||
com.google.api-client:google-api-client-java6:1.27.0
|
||||
@@ -50,6 +58,7 @@ com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
|
||||
com.google.apis:google-api-services-monitoring:v3-rev426-1.23.0
|
||||
com.google.apis:google-api-services-pubsub:v1-rev20181105-1.27.0
|
||||
com.google.apis:google-api-services-sheets:v4-rev483-1.22.0
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev56-1.23.0
|
||||
com.google.apis:google-api-services-storage:v1-rev20181109-1.27.0
|
||||
com.google.appengine.tools:appengine-gcs-client:0.6
|
||||
com.google.appengine.tools:appengine-mapreduce:0.9
|
||||
@@ -65,6 +74,8 @@ com.google.cloud.bigdataoss:gcsio:1.9.16
|
||||
com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
@@ -212,11 +223,11 @@ org.mockito:mockito-core:1.9.5
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
org.objenesis:objenesis:1.2
|
||||
org.ow2.asm:asm-analysis:6.0
|
||||
org.ow2.asm:asm-analysis:7.0
|
||||
org.ow2.asm:asm-commons:6.0
|
||||
org.ow2.asm:asm-tree:6.0
|
||||
org.ow2.asm:asm-util:6.0
|
||||
org.ow2.asm:asm:6.0
|
||||
org.ow2.asm:asm-tree:7.0
|
||||
org.ow2.asm:asm-util:7.0
|
||||
org.ow2.asm:asm:7.0
|
||||
org.postgresql:postgresql:42.2.6
|
||||
org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
|
||||
@@ -10,6 +10,14 @@ 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.github.jnr:jffi:1.2.17
|
||||
com.github.jnr:jnr-a64asm:1.0.0
|
||||
com.github.jnr:jnr-constants:0.9.11
|
||||
com.github.jnr:jnr-enxio:0.19
|
||||
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-jackson2:1.27.0
|
||||
com.google.api-client:google-api-client-java6:1.27.0
|
||||
@@ -50,6 +58,7 @@ com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
|
||||
com.google.apis:google-api-services-monitoring:v3-rev426-1.23.0
|
||||
com.google.apis:google-api-services-pubsub:v1-rev20181105-1.27.0
|
||||
com.google.apis:google-api-services-sheets:v4-rev483-1.22.0
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev56-1.23.0
|
||||
com.google.apis:google-api-services-storage:v1-rev20181109-1.27.0
|
||||
com.google.appengine.tools:appengine-gcs-client:0.6
|
||||
com.google.appengine.tools:appengine-mapreduce:0.9
|
||||
@@ -65,6 +74,8 @@ com.google.cloud.bigdataoss:gcsio:1.9.16
|
||||
com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
@@ -212,11 +223,11 @@ org.mockito:mockito-core:1.9.5
|
||||
org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
org.objenesis:objenesis:1.2
|
||||
org.ow2.asm:asm-analysis:6.0
|
||||
org.ow2.asm:asm-analysis:7.0
|
||||
org.ow2.asm:asm-commons:6.0
|
||||
org.ow2.asm:asm-tree:6.0
|
||||
org.ow2.asm:asm-util:6.0
|
||||
org.ow2.asm:asm:6.0
|
||||
org.ow2.asm:asm-tree:7.0
|
||||
org.ow2.asm:asm-util:7.0
|
||||
org.ow2.asm:asm:7.0
|
||||
org.postgresql:postgresql:42.2.6
|
||||
org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
|
||||
@@ -10,6 +10,14 @@ 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.github.jnr:jffi:1.2.17
|
||||
com.github.jnr:jnr-a64asm:1.0.0
|
||||
com.github.jnr:jnr-constants:0.9.11
|
||||
com.github.jnr:jnr-enxio:0.19
|
||||
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-jackson2:1.27.0
|
||||
com.google.api-client:google-api-client-java6:1.27.0
|
||||
@@ -50,6 +58,7 @@ com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
|
||||
com.google.apis:google-api-services-monitoring:v3-rev426-1.23.0
|
||||
com.google.apis:google-api-services-pubsub:v1-rev20181105-1.27.0
|
||||
com.google.apis:google-api-services-sheets:v4-rev483-1.22.0
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev56-1.23.0
|
||||
com.google.apis:google-api-services-storage:v1-rev20181109-1.27.0
|
||||
com.google.appengine.tools:appengine-gcs-client:0.6
|
||||
com.google.appengine.tools:appengine-mapreduce:0.9
|
||||
@@ -66,6 +75,8 @@ com.google.cloud.bigdataoss:gcsio:1.9.16
|
||||
com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
@@ -244,11 +255,11 @@ org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
org.objenesis:objenesis:2.6
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
org.ow2.asm:asm-analysis:6.0
|
||||
org.ow2.asm:asm-analysis:7.0
|
||||
org.ow2.asm:asm-commons:6.0
|
||||
org.ow2.asm:asm-tree:6.0
|
||||
org.ow2.asm:asm-util:6.0
|
||||
org.ow2.asm:asm:6.0
|
||||
org.ow2.asm:asm-tree:7.0
|
||||
org.ow2.asm:asm-util:7.0
|
||||
org.ow2.asm:asm:7.0
|
||||
org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
org.rnorth:tcp-unix-socket-proxy:1.0.2
|
||||
|
||||
@@ -10,6 +10,14 @@ 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.github.jnr:jffi:1.2.17
|
||||
com.github.jnr:jnr-a64asm:1.0.0
|
||||
com.github.jnr:jnr-constants:0.9.11
|
||||
com.github.jnr:jnr-enxio:0.19
|
||||
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-jackson2:1.27.0
|
||||
com.google.api-client:google-api-client-java6:1.27.0
|
||||
@@ -50,6 +58,7 @@ com.google.apis:google-api-services-groupssettings:v1-rev60-1.22.0
|
||||
com.google.apis:google-api-services-monitoring:v3-rev426-1.23.0
|
||||
com.google.apis:google-api-services-pubsub:v1-rev20181105-1.27.0
|
||||
com.google.apis:google-api-services-sheets:v4-rev483-1.22.0
|
||||
com.google.apis:google-api-services-sqladmin:v1beta4-rev56-1.23.0
|
||||
com.google.apis:google-api-services-storage:v1-rev20181109-1.27.0
|
||||
com.google.appengine.tools:appengine-gcs-client:0.6
|
||||
com.google.appengine.tools:appengine-mapreduce:0.9
|
||||
@@ -66,6 +75,8 @@ com.google.cloud.bigdataoss:gcsio:1.9.16
|
||||
com.google.cloud.bigdataoss:util:1.9.16
|
||||
com.google.cloud.bigtable:bigtable-client-core:1.8.0
|
||||
com.google.cloud.datastore:datastore-v1-proto-client:1.6.0
|
||||
com.google.cloud.sql:jdbc-socket-factory-core:1.0.12
|
||||
com.google.cloud.sql:postgres-socket-factory:1.0.12
|
||||
com.google.cloud:google-cloud-bigquerystorage:0.79.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable-admin:0.73.0-alpha
|
||||
com.google.cloud:google-cloud-bigtable:0.73.0-alpha
|
||||
@@ -242,11 +253,11 @@ org.mortbay.jetty:jetty-util:6.1.26
|
||||
org.mortbay.jetty:jetty:6.1.26
|
||||
org.objenesis:objenesis:2.6
|
||||
org.opentest4j:opentest4j:1.2.0
|
||||
org.ow2.asm:asm-analysis:6.0
|
||||
org.ow2.asm:asm-analysis:7.0
|
||||
org.ow2.asm:asm-commons:6.0
|
||||
org.ow2.asm:asm-tree:6.0
|
||||
org.ow2.asm:asm-util:6.0
|
||||
org.ow2.asm:asm:6.0
|
||||
org.ow2.asm:asm-tree:7.0
|
||||
org.ow2.asm:asm-util:7.0
|
||||
org.ow2.asm:asm:7.0
|
||||
org.rnorth.duct-tape:duct-tape:1.0.8
|
||||
org.rnorth.visible-assertions:visible-assertions:2.1.2
|
||||
org.rnorth:tcp-unix-socket-proxy:1.0.2
|
||||
|
||||
@@ -21,6 +21,7 @@ import static google.registry.batch.AsyncTaskEnqueuer.PARAM_RESOURCE_KEY;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_ACTIONS;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_DELETE;
|
||||
import static google.registry.batch.AsyncTaskEnqueuer.QUEUE_ASYNC_HOST_RENAME;
|
||||
import static google.registry.request.RequestParameters.extractLongParameter;
|
||||
import static google.registry.request.RequestParameters.extractOptionalBooleanParameter;
|
||||
import static google.registry.request.RequestParameters.extractOptionalIntParameter;
|
||||
import static google.registry.request.RequestParameters.extractOptionalParameter;
|
||||
@@ -40,9 +41,7 @@ import javax.inject.Named;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import org.joda.time.DateTime;
|
||||
|
||||
/**
|
||||
* Dagger module for injecting common settings for batch actions.
|
||||
*/
|
||||
/** Dagger module for injecting common settings for batch actions. */
|
||||
@Module
|
||||
public class BatchModule {
|
||||
|
||||
@@ -94,6 +93,12 @@ public class BatchModule {
|
||||
return extractSetOfDatetimeParameters(req, PARAM_RESAVE_TIMES);
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Parameter("oldUnlockRevisionId")
|
||||
static long provideOldUnlockRevisionId(HttpServletRequest req) {
|
||||
return extractLongParameter(req, "oldUnlockRevisionId");
|
||||
}
|
||||
|
||||
@Provides
|
||||
@Named(QUEUE_ASYNC_ACTIONS)
|
||||
static Queue provideAsyncActionsPushQueue() {
|
||||
|
||||
@@ -0,0 +1,167 @@
|
||||
// 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.batch;
|
||||
|
||||
import static com.google.common.base.Preconditions.checkArgument;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.request.Action.Method.POST;
|
||||
import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STATUSES;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_OK;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import com.google.common.flogger.FluentLogger;
|
||||
import com.google.common.net.MediaType;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.eppcommon.StatusValue;
|
||||
import google.registry.model.registry.RegistryLockDao;
|
||||
import google.registry.request.Action;
|
||||
import google.registry.request.Parameter;
|
||||
import google.registry.request.Response;
|
||||
import google.registry.request.auth.Auth;
|
||||
import google.registry.schema.domain.RegistryLock;
|
||||
import google.registry.tools.DomainLockUtils;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import javax.inject.Inject;
|
||||
|
||||
/**
|
||||
* Task that relocks a previously-Registry-Locked domain after some predetermined period of time.
|
||||
*/
|
||||
@Action(
|
||||
service = Action.Service.BACKEND,
|
||||
path = RelockDomainAction.PATH,
|
||||
method = POST,
|
||||
automaticallyPrintOk = true,
|
||||
auth = Auth.AUTH_INTERNAL_OR_ADMIN)
|
||||
public class RelockDomainAction implements Runnable {
|
||||
|
||||
public static final String PATH = "/_dr/task/relockDomain";
|
||||
|
||||
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
|
||||
|
||||
private final long oldUnlockRevisionId;
|
||||
private final DomainLockUtils domainLockUtils;
|
||||
private final Response response;
|
||||
|
||||
@Inject
|
||||
public RelockDomainAction(
|
||||
@Parameter("oldUnlockRevisionId") long oldUnlockRevisionId,
|
||||
DomainLockUtils domainLockUtils,
|
||||
Response response) {
|
||||
this.oldUnlockRevisionId = oldUnlockRevisionId;
|
||||
this.domainLockUtils = domainLockUtils;
|
||||
this.response = response;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
jpaTm().transact(this::relockDomain);
|
||||
}
|
||||
|
||||
private void relockDomain() {
|
||||
RegistryLock oldLock;
|
||||
try {
|
||||
oldLock =
|
||||
RegistryLockDao.getByRevisionId(oldUnlockRevisionId)
|
||||
.orElseThrow(
|
||||
() ->
|
||||
new IllegalArgumentException(
|
||||
String.format("Unknown revision ID %d", oldUnlockRevisionId)));
|
||||
DomainBase domain =
|
||||
ofy()
|
||||
.load()
|
||||
.type(DomainBase.class)
|
||||
.id(oldLock.getRepoId())
|
||||
.now()
|
||||
.cloneProjectedAtTime(jpaTm().getTransactionTime());
|
||||
|
||||
if (domain.getStatusValues().containsAll(REGISTRY_LOCK_STATUSES)
|
||||
|| oldLock.getRelock() != null) {
|
||||
// The domain was manually locked, so we shouldn't worry about relocking
|
||||
String message =
|
||||
String.format(
|
||||
"Domain %s is already manually relocked, skipping automated relock.",
|
||||
domain.getFullyQualifiedDomainName());
|
||||
logger.atInfo().log(message);
|
||||
// SC_NO_CONTENT (204) skips retry -- see the comment below
|
||||
response.setStatus(SC_NO_CONTENT);
|
||||
response.setContentType(MediaType.PLAIN_TEXT_UTF_8);
|
||||
response.setPayload(message);
|
||||
return;
|
||||
}
|
||||
verifyDomainAndLockState(oldLock, domain);
|
||||
} catch (Throwable t) {
|
||||
/* If there's a bad verification code or the domain is in a bad state, we won't want to retry.
|
||||
* AppEngine will retry on non-2xx error codes, so we return SC_NO_CONTENT (204) to avoid it.
|
||||
*
|
||||
* See https://cloud.google.com/appengine/docs/standard/java/taskqueue/push/retrying-tasks
|
||||
* for more details on retry behavior. */
|
||||
logger.atWarning().withCause(t).log(
|
||||
"Exception when attempting to relock domain with old revision ID %d.",
|
||||
oldUnlockRevisionId);
|
||||
response.setStatus(SC_NO_CONTENT);
|
||||
response.setContentType(MediaType.PLAIN_TEXT_UTF_8);
|
||||
response.setPayload(String.format("Relock failed: %s", t.getMessage()));
|
||||
return;
|
||||
}
|
||||
applyRelock(oldLock);
|
||||
}
|
||||
|
||||
private void applyRelock(RegistryLock oldLock) {
|
||||
try {
|
||||
domainLockUtils.administrativelyApplyLock(
|
||||
oldLock.getDomainName(),
|
||||
oldLock.getRegistrarId(),
|
||||
oldLock.getRegistrarPocId(),
|
||||
oldLock.isSuperuser());
|
||||
logger.atInfo().log("Relocked domain %s.", oldLock.getDomainName());
|
||||
response.setStatus(SC_OK);
|
||||
} catch (Throwable t) {
|
||||
// Any errors that occur here are unexpected, so we should retry. Return a non-2xx
|
||||
// error code to get AppEngine to retry
|
||||
logger.atSevere().withCause(t).log(
|
||||
"Exception when attempting to relock domain %s.", oldLock.getDomainName());
|
||||
response.setStatus(SC_INTERNAL_SERVER_ERROR);
|
||||
response.setContentType(MediaType.PLAIN_TEXT_UTF_8);
|
||||
response.setPayload(String.format("Relock failed: %s", t.getMessage()));
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyDomainAndLockState(RegistryLock oldLock, DomainBase domain) {
|
||||
// Domain shouldn't be deleted or have a pending transfer/delete
|
||||
String domainName = domain.getFullyQualifiedDomainName();
|
||||
checkArgument(
|
||||
!DateTimeUtils.isAtOrAfter(jpaTm().getTransactionTime(), domain.getDeletionTime()),
|
||||
"Domain %s has been deleted",
|
||||
domainName);
|
||||
ImmutableSet<StatusValue> statusValues = domain.getStatusValues();
|
||||
checkArgument(
|
||||
!statusValues.contains(StatusValue.PENDING_DELETE),
|
||||
"Domain %s has a pending delete",
|
||||
domainName);
|
||||
checkArgument(
|
||||
!statusValues.contains(StatusValue.PENDING_TRANSFER),
|
||||
"Domain %s has a pending transfer",
|
||||
domainName);
|
||||
checkArgument(
|
||||
domain.getCurrentSponsorClientId().equals(oldLock.getRegistrarId()),
|
||||
"Domain %s has been transferred from registrar %s to registrar %s since the unlock",
|
||||
domainName,
|
||||
oldLock.getRegistrarId(),
|
||||
domain.getCurrentSponsorClientId());
|
||||
}
|
||||
}
|
||||
@@ -25,6 +25,12 @@ import javax.persistence.EntityManager;
|
||||
/** Data access object for {@link google.registry.schema.domain.RegistryLock}. */
|
||||
public final class RegistryLockDao {
|
||||
|
||||
/** Returns the {@link RegistryLock} referred to by this revision ID, or empty if none exists. */
|
||||
public static Optional<RegistryLock> getByRevisionId(long revisionId) {
|
||||
jpaTm().assertInTransaction();
|
||||
return Optional.ofNullable(jpaTm().getEntityManager().find(RegistryLock.class, revisionId));
|
||||
}
|
||||
|
||||
/** Returns the most recent version of the {@link RegistryLock} referred to by the code. */
|
||||
public static Optional<RegistryLock> getByVerificationCode(String verificationCode) {
|
||||
jpaTm().assertInTransaction();
|
||||
@@ -46,8 +52,10 @@ public final class RegistryLockDao {
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createQuery(
|
||||
"SELECT lock FROM RegistryLock lock WHERE lock.registrarId = :registrarId"
|
||||
+ " AND lock.unlockCompletionTimestamp IS NULL",
|
||||
"SELECT lock FROM RegistryLock lock"
|
||||
+ " WHERE lock.registrarId = :registrarId"
|
||||
+ " AND lock.unlockCompletionTimestamp IS NULL"
|
||||
+ " ORDER BY lock.domainName ASC",
|
||||
RegistryLock.class)
|
||||
.setParameter("registrarId", registrarId)
|
||||
.getResultList());
|
||||
@@ -84,7 +92,29 @@ public final class RegistryLockDao {
|
||||
.getEntityManager()
|
||||
.createQuery(
|
||||
"SELECT lock FROM RegistryLock lock WHERE lock.repoId = :repoId AND"
|
||||
+ " lock.lockCompletionTimestamp IS NOT NULL ORDER BY lock.revisionId"
|
||||
+ " lock.lockCompletionTimestamp IS NOT NULL AND"
|
||||
+ " lock.unlockCompletionTimestamp IS NULL ORDER BY lock.revisionId"
|
||||
+ " DESC",
|
||||
RegistryLock.class)
|
||||
.setParameter("repoId", repoId)
|
||||
.setMaxResults(1)
|
||||
.getResultStream()
|
||||
.findFirst();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the most recent verified unlock for a given domain specified by repo ID.
|
||||
*
|
||||
* <p>Returns empty if no unlock has ever been finalized for this domain. This is different from
|
||||
* {@link #getMostRecentByRepoId(String)} in that it only returns verified unlocks.
|
||||
*/
|
||||
public static Optional<RegistryLock> getMostRecentVerifiedUnlockByRepoId(String repoId) {
|
||||
jpaTm().assertInTransaction();
|
||||
return jpaTm()
|
||||
.getEntityManager()
|
||||
.createQuery(
|
||||
"SELECT lock FROM RegistryLock lock WHERE lock.repoId = :repoId AND"
|
||||
+ " lock.unlockCompletionTimestamp IS NOT NULL ORDER BY lock.revisionId"
|
||||
+ " DESC",
|
||||
RegistryLock.class)
|
||||
.setParameter("repoId", repoId)
|
||||
|
||||
@@ -26,6 +26,7 @@ import google.registry.batch.DeleteLoadTestDataAction;
|
||||
import google.registry.batch.DeleteProberDataAction;
|
||||
import google.registry.batch.ExpandRecurringBillingEventsAction;
|
||||
import google.registry.batch.RefreshDnsOnHostRenameAction;
|
||||
import google.registry.batch.RelockDomainAction;
|
||||
import google.registry.batch.ResaveAllEppResourcesAction;
|
||||
import google.registry.batch.ResaveEntityAction;
|
||||
import google.registry.cron.CommitLogFanoutAction;
|
||||
@@ -140,6 +141,7 @@ interface BackendRequestComponent {
|
||||
RdeReporter rdeReporter();
|
||||
RefreshDnsAction refreshDnsAction();
|
||||
RefreshDnsOnHostRenameAction refreshDnsOnHostRenameAction();
|
||||
RelockDomainAction relockDomainAction();
|
||||
ResaveAllEppResourcesAction resaveAllEppResourcesAction();
|
||||
ResaveEntityAction resaveEntityAction();
|
||||
SyncGroupMembersAction syncGroupMembersAction();
|
||||
|
||||
@@ -19,7 +19,6 @@ import google.registry.config.CredentialModule;
|
||||
import google.registry.config.RegistryConfig.ConfigModule;
|
||||
import google.registry.keyring.kms.KmsModule;
|
||||
import google.registry.persistence.PersistenceModule.AppEngineJpaTm;
|
||||
import google.registry.persistence.PersistenceModule.NomulusToolJpaTm;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
import google.registry.util.UtilsModule;
|
||||
import javax.inject.Singleton;
|
||||
@@ -39,7 +38,4 @@ public interface PersistenceComponent {
|
||||
|
||||
@AppEngineJpaTm
|
||||
JpaTransactionManager appEngineJpaTransactionManager();
|
||||
|
||||
@NomulusToolJpaTm
|
||||
JpaTransactionManager nomulusToolJpaTransactionManager();
|
||||
}
|
||||
|
||||
@@ -22,6 +22,7 @@ import static google.registry.config.RegistryConfig.getHibernateHikariMaximumPoo
|
||||
import static google.registry.config.RegistryConfig.getHibernateHikariMinimumIdle;
|
||||
import static google.registry.config.RegistryConfig.getHibernateLogSqlQueries;
|
||||
|
||||
import com.google.api.client.auth.oauth2.Credential;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Maps;
|
||||
@@ -29,8 +30,10 @@ import dagger.Module;
|
||||
import dagger.Provides;
|
||||
import google.registry.config.RegistryConfig.Config;
|
||||
import google.registry.keyring.kms.KmsKeyring;
|
||||
import google.registry.persistence.transaction.CloudSqlCredentialSupplier;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
import google.registry.persistence.transaction.JpaTransactionManagerImpl;
|
||||
import google.registry.tools.AuthModule.CloudSqlClientCredential;
|
||||
import google.registry.util.Clock;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.util.HashMap;
|
||||
@@ -118,7 +121,9 @@ public class PersistenceModule {
|
||||
@Config("toolsCloudSqlUsername") String username,
|
||||
KmsKeyring kmsKeyring,
|
||||
@PartialCloudSqlConfigs ImmutableMap<String, String> cloudSqlConfigs,
|
||||
@CloudSqlClientCredential Credential credential,
|
||||
Clock clock) {
|
||||
CloudSqlCredentialSupplier.setupCredentialSupplier(credential);
|
||||
HashMap<String, String> overrides = Maps.newHashMap(cloudSqlConfigs);
|
||||
overrides.put(Environment.USER, username);
|
||||
overrides.put(Environment.PASS, kmsKeyring.getToolsCloudSqlPassword());
|
||||
@@ -158,7 +163,7 @@ public class PersistenceModule {
|
||||
/** Dagger qualifier for {@link JpaTransactionManager} used for Nomulus tool. */
|
||||
@Qualifier
|
||||
@Documented
|
||||
@interface NomulusToolJpaTm {}
|
||||
public @interface NomulusToolJpaTm {}
|
||||
|
||||
/** Dagger qualifier for the partial Cloud SQL configs. */
|
||||
@Qualifier
|
||||
|
||||
@@ -43,11 +43,11 @@ public class VKey<T> extends ImmutableObject {
|
||||
return new VKey(kind, ofyKey, primaryKey);
|
||||
}
|
||||
|
||||
public static <T> VKey<T> create(Class<? extends T> kind, Object primaryKey) {
|
||||
public static <T> VKey<T> createSql(Class<? extends T> kind, Object primaryKey) {
|
||||
return new VKey(kind, null, primaryKey);
|
||||
}
|
||||
|
||||
public static <T> VKey<T> create(
|
||||
public static <T> VKey<T> createOfy(
|
||||
Class<? extends T> kind, com.googlecode.objectify.Key<T> ofyKey) {
|
||||
return new VKey(kind, ofyKey, null);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
// 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.converter;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.AttributeConverter;
|
||||
import javax.persistence.Converter;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/** JPA converter to for storing/retrieving {@link org.joda.time.DateTime} objects. */
|
||||
@Converter(autoApply = true)
|
||||
public class DurationConverter implements AttributeConverter<Duration, Long> {
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Long convertToDatabaseColumn(@Nullable Duration duration) {
|
||||
return duration == null ? null : duration.getMillis();
|
||||
}
|
||||
|
||||
@Override
|
||||
@Nullable
|
||||
public Duration convertToEntityAttribute(@Nullable Long dbData) {
|
||||
return dbData == null ? null : new Duration(dbData);
|
||||
}
|
||||
}
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
// 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.transaction;
|
||||
|
||||
import com.google.api.client.auth.oauth2.Credential;
|
||||
import com.google.cloud.sql.CredentialFactory;
|
||||
|
||||
/** Supplier class to provide {@link Credential} for Cloud SQL library. */
|
||||
public class CloudSqlCredentialSupplier implements CredentialFactory {
|
||||
private static Credential credential;
|
||||
|
||||
/** Initialize the supplier with given credential json and scopes. */
|
||||
public static void setupCredentialSupplier(Credential credential) {
|
||||
System.setProperty(
|
||||
CredentialFactory.CREDENTIAL_FACTORY_PROPERTY, CloudSqlCredentialSupplier.class.getName());
|
||||
CloudSqlCredentialSupplier.credential = credential;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Credential create() {
|
||||
return credential;
|
||||
}
|
||||
}
|
||||
+4
-7
@@ -16,11 +16,9 @@ package google.registry.persistence.transaction;
|
||||
|
||||
import com.google.appengine.api.utils.SystemProperty;
|
||||
import com.google.appengine.api.utils.SystemProperty.Environment.Value;
|
||||
import com.google.common.annotations.VisibleForTesting;
|
||||
import com.google.common.base.Suppliers;
|
||||
import google.registry.model.ofy.DatastoreTransactionManager;
|
||||
import google.registry.persistence.DaggerPersistenceComponent;
|
||||
import google.registry.tools.RegistryToolEnvironment;
|
||||
import google.registry.util.NonFinalForTesting;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
@@ -38,11 +36,10 @@ public class TransactionManagerFactory {
|
||||
private TransactionManagerFactory() {}
|
||||
|
||||
private static JpaTransactionManager createJpaTransactionManager() {
|
||||
// If we are running a nomulus command, jpaTm will be injected in RegistryCli.java
|
||||
// by calling setJpaTm().
|
||||
if (isInAppEngine()) {
|
||||
return DaggerPersistenceComponent.create().appEngineJpaTransactionManager();
|
||||
} else if (RegistryToolEnvironment.isInRegistryTool()
|
||||
&& RegistryToolEnvironment.isJpaTmEnabled()) {
|
||||
return DaggerPersistenceComponent.create().nomulusToolJpaTransactionManager();
|
||||
} else {
|
||||
return DummyJpaTransactionManager.create();
|
||||
}
|
||||
@@ -78,8 +75,8 @@ public class TransactionManagerFactory {
|
||||
return jpaTm.get();
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
static void setJpaTmForTesting(JpaTransactionManager newJpaTm) {
|
||||
/** Sets the return of {@link #jpaTm()} to the given instance of {@link JpaTransactionManager}. */
|
||||
public static void setJpaTm(JpaTransactionManager newJpaTm) {
|
||||
jpaTm = Suppliers.ofInstance(newJpaTm);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -193,8 +193,7 @@ public class PublishSpec11ReportAction implements Runnable {
|
||||
// Group by email address then flat-map all of the ThreatMatch objects together
|
||||
return ImmutableMap.copyOf(
|
||||
Maps.transformValues(
|
||||
Multimaps.index(registrarThreatMatches, RegistrarThreatMatches::clientId)
|
||||
.asMap(),
|
||||
Multimaps.index(registrarThreatMatches, RegistrarThreatMatches::clientId).asMap(),
|
||||
registrarThreatMatchesCollection ->
|
||||
registrarThreatMatchesCollection.stream()
|
||||
.flatMap(matches -> matches.threatMatches().stream())
|
||||
|
||||
@@ -44,11 +44,11 @@ public final class RequestParameters {
|
||||
* method to yield the following results:
|
||||
*
|
||||
* <ul>
|
||||
* <li>/foo?bar=hello → hello
|
||||
* <li>/foo?bar=hello&bar=there → hello
|
||||
* <li>/foo?bar= → 400 error (empty)
|
||||
* <li>/foo?bar=&bar=there → 400 error (empty)
|
||||
* <li>/foo → 400 error (absent)
|
||||
* <li>/foo?bar=hello → hello
|
||||
* <li>/foo?bar=hello&bar=there → hello
|
||||
* <li>/foo?bar= → 400 error (empty)
|
||||
* <li>/foo?bar=&bar=there → 400 error (empty)
|
||||
* <li>/foo → 400 error (absent)
|
||||
* </ul>
|
||||
*
|
||||
* @throws BadRequestException if request parameter is absent or empty
|
||||
@@ -88,10 +88,27 @@ public final class RequestParameters {
|
||||
* @throws BadRequestException if request parameter is absent, empty, or not a valid integer
|
||||
*/
|
||||
public static int extractIntParameter(HttpServletRequest req, String name) {
|
||||
String stringParam = req.getParameter(name);
|
||||
try {
|
||||
return Integer.parseInt(nullToEmpty(req.getParameter(name)));
|
||||
return Integer.parseInt(nullToEmpty(stringParam));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new BadRequestException("Expected integer: " + name);
|
||||
throw new BadRequestException(
|
||||
String.format("Expected int for parameter %s but received %s", name, stringParam));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns first GET or POST parameter associated with {@code name} as a long.
|
||||
*
|
||||
* @throws BadRequestException if request parameter is absent, empty, or not a valid long
|
||||
*/
|
||||
public static long extractLongParameter(HttpServletRequest req, String name) {
|
||||
String stringParam = req.getParameter(name);
|
||||
try {
|
||||
return Long.parseLong(nullToEmpty(stringParam));
|
||||
} catch (NumberFormatException e) {
|
||||
throw new BadRequestException(
|
||||
String.format("Expected long for parameter %s but received %s", name, stringParam));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -126,9 +143,7 @@ public final class RequestParameters {
|
||||
if (parameter == null || parameter.isEmpty()) {
|
||||
return ImmutableSet.of();
|
||||
}
|
||||
return Splitter.on(',')
|
||||
.splitToList(parameter)
|
||||
.stream()
|
||||
return Splitter.on(',').splitToList(parameter).stream()
|
||||
.filter(s -> !s.isEmpty())
|
||||
.collect(toImmutableSet());
|
||||
}
|
||||
@@ -160,8 +175,8 @@ public final class RequestParameters {
|
||||
* @throws BadRequestException if request parameter named {@code name} is absent, empty, or not
|
||||
* equal to any of the values in {@code enumClass}
|
||||
*/
|
||||
public static <C extends Enum<C>>
|
||||
C extractEnumParameter(HttpServletRequest req, Class<C> enumClass, String name) {
|
||||
public static <C extends Enum<C>> C extractEnumParameter(
|
||||
HttpServletRequest req, Class<C> enumClass, String name) {
|
||||
return getEnumValue(enumClass, extractRequiredParameter(req, name), name);
|
||||
}
|
||||
|
||||
@@ -216,9 +231,9 @@ public final class RequestParameters {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns first request parameter associated with {@code name} parsed as an
|
||||
* <a href="https://goo.gl/pk5Q2k">ISO 8601</a> timestamp, e.g. {@code 1984-12-18TZ},
|
||||
* {@code 2000-01-01T16:20:00Z}.
|
||||
* Returns first request parameter associated with {@code name} parsed as an <a
|
||||
* href="https://goo.gl/pk5Q2k">ISO 8601</a> timestamp, e.g. {@code 1984-12-18TZ}, {@code
|
||||
* 2000-01-01T16:20:00Z}.
|
||||
*
|
||||
* @throws BadRequestException if request parameter named {@code name} is absent, empty, or could
|
||||
* not be parsed as an ISO 8601 timestamp
|
||||
@@ -233,9 +248,9 @@ public final class RequestParameters {
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns first request parameter associated with {@code name} parsed as an
|
||||
* <a href="https://goo.gl/pk5Q2k">ISO 8601</a> timestamp, e.g. {@code 1984-12-18TZ},
|
||||
* {@code 2000-01-01T16:20:00Z}.
|
||||
* Returns first request parameter associated with {@code name} parsed as an <a
|
||||
* href="https://goo.gl/pk5Q2k">ISO 8601</a> timestamp, e.g. {@code 1984-12-18TZ}, {@code
|
||||
* 2000-01-01T16:20:00Z}.
|
||||
*
|
||||
* @throws BadRequestException if request parameter is present but not a valid {@link DateTime}.
|
||||
*/
|
||||
@@ -262,8 +277,7 @@ public final class RequestParameters {
|
||||
public static ImmutableSet<DateTime> extractSetOfDatetimeParameters(
|
||||
HttpServletRequest req, String name) {
|
||||
try {
|
||||
return extractSetOfParameters(req, name)
|
||||
.stream()
|
||||
return extractSetOfParameters(req, name).stream()
|
||||
.filter(not(String::isEmpty))
|
||||
.map(DateTime::parse)
|
||||
.collect(toImmutableSet());
|
||||
|
||||
@@ -26,14 +26,19 @@ import google.registry.model.UpdateAutoTimestamp;
|
||||
import google.registry.util.DateTimeUtils;
|
||||
import java.time.ZonedDateTime;
|
||||
import java.util.Optional;
|
||||
import javax.annotation.Nullable;
|
||||
import javax.persistence.Column;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.FetchType;
|
||||
import javax.persistence.GeneratedValue;
|
||||
import javax.persistence.GenerationType;
|
||||
import javax.persistence.Id;
|
||||
import javax.persistence.Index;
|
||||
import javax.persistence.JoinColumn;
|
||||
import javax.persistence.OneToOne;
|
||||
import javax.persistence.Table;
|
||||
import org.joda.time.DateTime;
|
||||
import org.joda.time.Duration;
|
||||
|
||||
/**
|
||||
* Represents a registry lock/unlock object, meaning that the domain is locked on the registry
|
||||
@@ -123,6 +128,14 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
|
||||
@Column(nullable = false)
|
||||
private boolean isSuperuser;
|
||||
|
||||
/** The lock that undoes this lock, if this lock has been unlocked and the domain locked again. */
|
||||
@OneToOne(fetch = FetchType.LAZY)
|
||||
@JoinColumn(name = "relockRevisionId", referencedColumnName = "revisionId")
|
||||
private RegistryLock relock;
|
||||
|
||||
/** The duration after which we will re-lock this domain after it is unlocked. */
|
||||
private Duration relockDuration;
|
||||
|
||||
/** Time that this entity was last updated. */
|
||||
private UpdateAutoTimestamp lastUpdateTimestamp;
|
||||
|
||||
@@ -179,6 +192,21 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
|
||||
return revisionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* The lock that undoes this lock, if this lock has been unlocked and the domain locked again.
|
||||
*
|
||||
* <p>Note: this is lazily loaded, so it may not be initialized if referenced outside of the
|
||||
* transaction in which this lock is loaded.
|
||||
*/
|
||||
public RegistryLock getRelock() {
|
||||
return relock;
|
||||
}
|
||||
|
||||
/** The duration after which we will re-lock this domain after it is unlocked. */
|
||||
public Optional<Duration> getRelockDuration() {
|
||||
return Optional.ofNullable(relockDuration);
|
||||
}
|
||||
|
||||
public boolean isLocked() {
|
||||
return lockCompletionTimestamp != null && unlockCompletionTimestamp == null;
|
||||
}
|
||||
@@ -266,5 +294,15 @@ public final class RegistryLock extends ImmutableObject implements Buildable {
|
||||
getInstance().isSuperuser = isSuperuser;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRelock(RegistryLock relock) {
|
||||
getInstance().relock = relock;
|
||||
return this;
|
||||
}
|
||||
|
||||
public Builder setRelockDuration(@Nullable Duration relockDuration) {
|
||||
getInstance().relockDuration = relockDuration;
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import com.google.api.client.auth.oauth2.Credential;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets.Details;
|
||||
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
|
||||
import com.google.api.client.http.javanet.NetHttpTransport;
|
||||
import com.google.api.client.json.JsonFactory;
|
||||
import com.google.api.client.util.store.AbstractDataStoreFactory;
|
||||
@@ -42,6 +43,7 @@ import google.registry.util.GoogleCredentialsBundle;
|
||||
import java.io.ByteArrayInputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.lang.annotation.Documented;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
@@ -92,6 +94,26 @@ public class AuthModule {
|
||||
}
|
||||
}
|
||||
|
||||
// TODO(b/138195359): Deprecate this credential once Cloud SQL socket library uses the new auth
|
||||
// library.
|
||||
@Provides
|
||||
@CloudSqlClientCredential
|
||||
public static Credential providesLocalCredentialForCloudSqlClient(
|
||||
@LocalCredentialJson String credentialJson,
|
||||
@Config("localCredentialOauthScopes") ImmutableList<String> credentialScopes) {
|
||||
try {
|
||||
GoogleCredential credential =
|
||||
GoogleCredential.fromStream(new ByteArrayInputStream(credentialJson.getBytes(UTF_8)));
|
||||
if (credential.createScopedRequired()) {
|
||||
credential = credential.createScoped(credentialScopes);
|
||||
}
|
||||
return credential;
|
||||
} catch (IOException e) {
|
||||
throw new UncheckedIOException(
|
||||
"Error occurred while creating a GoogleCredential for Cloud SQL client", e);
|
||||
}
|
||||
}
|
||||
|
||||
@Provides
|
||||
public static GoogleAuthorizationCodeFlow provideAuthorizationCodeFlow(
|
||||
JsonFactory jsonFactory,
|
||||
@@ -184,6 +206,11 @@ public class AuthModule {
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
private @interface StoredCredential {}
|
||||
|
||||
/** Dagger qualifier for {@link Credential} used by the Cloud SQL client in the nomulus tool. */
|
||||
@Qualifier
|
||||
@Documented
|
||||
public @interface CloudSqlClientCredential {}
|
||||
|
||||
/** Dagger qualifier for the credential qualifier consisting of client and scopes. */
|
||||
@Qualifier
|
||||
@Documented
|
||||
|
||||
@@ -106,6 +106,7 @@ public final class DomainLockUtils {
|
||||
|
||||
RegistryLock newLock =
|
||||
RegistryLockDao.save(lock.asBuilder().setLockCompletionTimestamp(now).build());
|
||||
setAsRelock(newLock);
|
||||
tm().transact(() -> applyLockStatuses(newLock, now));
|
||||
return newLock;
|
||||
});
|
||||
@@ -149,13 +150,14 @@ public final class DomainLockUtils {
|
||||
.transact(
|
||||
() -> {
|
||||
DateTime now = jpaTm().getTransactionTime();
|
||||
RegistryLock result =
|
||||
RegistryLock newLock =
|
||||
RegistryLockDao.save(
|
||||
createLockBuilder(domainName, registrarId, registrarPocId, isAdmin)
|
||||
.setLockCompletionTimestamp(now)
|
||||
.build());
|
||||
tm().transact(() -> applyLockStatuses(result, now));
|
||||
return result;
|
||||
tm().transact(() -> applyLockStatuses(newLock, now));
|
||||
setAsRelock(newLock);
|
||||
return newLock;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -179,6 +181,16 @@ public final class DomainLockUtils {
|
||||
});
|
||||
}
|
||||
|
||||
private void setAsRelock(RegistryLock newLock) {
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
RegistryLockDao.getMostRecentVerifiedUnlockByRepoId(newLock.getRepoId())
|
||||
.ifPresent(
|
||||
oldLock ->
|
||||
RegistryLockDao.save(oldLock.asBuilder().setRelock(newLock).build())));
|
||||
}
|
||||
|
||||
private RegistryLock.Builder createLockBuilder(
|
||||
String domainName, String registrarId, @Nullable String registrarPocId, boolean isAdmin) {
|
||||
DateTime now = jpaTm().getTransactionTime();
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.Iterables;
|
||||
import google.registry.config.RegistryConfig;
|
||||
import google.registry.model.ofy.ObjectifyService;
|
||||
import google.registry.persistence.transaction.TransactionManagerFactory;
|
||||
import google.registry.tools.AuthModule.LoginRequiredException;
|
||||
import google.registry.tools.params.ParameterFactory;
|
||||
import java.io.ByteArrayInputStream;
|
||||
@@ -237,7 +238,7 @@ final class RegistryCli implements AutoCloseable, CommandRunner {
|
||||
// Enable Cloud SQL for command that needs remote API as they will very likely use
|
||||
// Cloud SQL after the database migration. Note that the DB password is stored in Datastore
|
||||
// and it is already initialized above.
|
||||
RegistryToolEnvironment.enableJpaTm();
|
||||
TransactionManagerFactory.setJpaTm(component.nomulusToolJpaTransactionManager());
|
||||
}
|
||||
|
||||
command.run();
|
||||
|
||||
@@ -27,6 +27,9 @@ import google.registry.keyring.KeyringModule;
|
||||
import google.registry.keyring.api.DummyKeyringModule;
|
||||
import google.registry.keyring.api.KeyModule;
|
||||
import google.registry.keyring.kms.KmsModule;
|
||||
import google.registry.persistence.PersistenceModule;
|
||||
import google.registry.persistence.PersistenceModule.NomulusToolJpaTm;
|
||||
import google.registry.persistence.transaction.JpaTransactionManager;
|
||||
import google.registry.rde.RdeModule;
|
||||
import google.registry.request.Modules.DatastoreServiceModule;
|
||||
import google.registry.request.Modules.Jackson2Module;
|
||||
@@ -63,6 +66,7 @@ import javax.inject.Singleton;
|
||||
KeyringModule.class,
|
||||
KmsModule.class,
|
||||
LocalCredentialModule.class,
|
||||
PersistenceModule.class,
|
||||
RdeModule.class,
|
||||
RequestFactoryModule.class,
|
||||
URLFetchServiceModule.class,
|
||||
@@ -70,7 +74,7 @@ import javax.inject.Singleton;
|
||||
UserServiceModule.class,
|
||||
UtilsModule.class,
|
||||
VoidDnsWriterModule.class,
|
||||
WhoisModule.class,
|
||||
WhoisModule.class
|
||||
})
|
||||
interface RegistryToolComponent {
|
||||
void inject(AckPollMessagesCommand command);
|
||||
@@ -117,6 +121,9 @@ interface RegistryToolComponent {
|
||||
@LocalCredentialJson
|
||||
String googleCredentialJson();
|
||||
|
||||
@NomulusToolJpaTm
|
||||
JpaTransactionManager nomulusToolJpaTransactionManager();
|
||||
|
||||
@Component.Builder
|
||||
interface Builder {
|
||||
@BindsInstance
|
||||
|
||||
@@ -23,7 +23,6 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import google.registry.config.RegistryEnvironment;
|
||||
import google.registry.config.SystemPropertySetter;
|
||||
import google.registry.persistence.transaction.TransactionManagerFactory;
|
||||
|
||||
/** Enum of production environments, used for the {@code --environment} flag. */
|
||||
public enum RegistryToolEnvironment {
|
||||
@@ -40,7 +39,6 @@ public enum RegistryToolEnvironment {
|
||||
|
||||
private static final ImmutableList<String> FLAGS = ImmutableList.of("-e", "--environment");
|
||||
private static RegistryToolEnvironment instance;
|
||||
private static boolean isJpaTmEnabled = false;
|
||||
private final RegistryEnvironment actualEnvironment;
|
||||
private final ImmutableMap<String, String> extraProperties;
|
||||
|
||||
@@ -100,26 +98,6 @@ public enum RegistryToolEnvironment {
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns true if the RegistryToolEnvironment is set up. */
|
||||
public static boolean isInRegistryTool() {
|
||||
return instance != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the flag to indicate that the running command needs JpaTransactionManager to be enabled.
|
||||
*/
|
||||
public static void enableJpaTm() {
|
||||
isJpaTmEnabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the JpaTransactionManager is enabled. Note that JpaTm is actually enabled in
|
||||
* {@link TransactionManagerFactory} by reading this flag.
|
||||
*/
|
||||
public static boolean isJpaTmEnabled() {
|
||||
return isJpaTmEnabled;
|
||||
}
|
||||
|
||||
/** Extracts value from command-line arguments associated with any {@code flags}. */
|
||||
private static String getFlagValue(String[] args, Iterable<String> flags) {
|
||||
for (String flag : flags) {
|
||||
|
||||
@@ -41,7 +41,6 @@ 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 java.util.Optional;
|
||||
@@ -117,41 +116,61 @@ public final class RegistryLockGetAction implements JsonGetAction {
|
||||
}
|
||||
}
|
||||
|
||||
private ImmutableMap<String, ?> getLockedDomainsMap(String clientId)
|
||||
throws RegistrarAccessDeniedException {
|
||||
// Note: admins always have access to the locks page
|
||||
checkArgument(authResult.userAuthInfo().isPresent(), "User auth info must be present");
|
||||
UserAuthInfo userAuthInfo = authResult.userAuthInfo().get();
|
||||
boolean isAdmin = registrarAccessor.isAdmin();
|
||||
Registrar registrar = getRegistrarAndVerifyLockAccess(clientId, isAdmin);
|
||||
User user = userAuthInfo.user();
|
||||
boolean isRegistryLockAllowed =
|
||||
isAdmin
|
||||
|| registrar.getContacts().stream()
|
||||
.filter(contact -> contact.getEmailAddress().equals(user.getEmail()))
|
||||
.findFirst()
|
||||
.map(RegistrarContact::isRegistryLockAllowed)
|
||||
.orElse(false);
|
||||
return ImmutableMap.of(
|
||||
LOCK_ENABLED_FOR_CONTACT_PARAM,
|
||||
isRegistryLockAllowed,
|
||||
EMAIL_PARAM,
|
||||
user.getEmail(),
|
||||
PARAM_CLIENT_ID,
|
||||
registrar.getClientId(),
|
||||
LOCKS_PARAM,
|
||||
getLockedDomains(clientId, isAdmin));
|
||||
static Optional<RegistrarContact> getContactMatchingLogin(User user, Registrar registrar) {
|
||||
ImmutableList<RegistrarContact> matchingContacts =
|
||||
registrar.getContacts().stream()
|
||||
.filter(contact -> contact.getGaeUserId().equals(user.getUserId()))
|
||||
.collect(toImmutableList());
|
||||
if (matchingContacts.size() > 1) {
|
||||
ImmutableList<String> matchingEmails =
|
||||
matchingContacts.stream()
|
||||
.map(RegistrarContact::getEmailAddress)
|
||||
.collect(toImmutableList());
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
"User ID %s had multiple matching contacts with email addresses %s",
|
||||
user.getUserId(), matchingEmails));
|
||||
}
|
||||
return matchingContacts.stream().findFirst();
|
||||
}
|
||||
|
||||
private Registrar getRegistrarAndVerifyLockAccess(String clientId, boolean isAdmin)
|
||||
static Registrar getRegistrarAndVerifyLockAccess(
|
||||
AuthenticatedRegistrarAccessor registrarAccessor, String clientId, boolean isAdmin)
|
||||
throws RegistrarAccessDeniedException {
|
||||
Registrar registrar = registrarAccessor.getRegistrar(clientId);
|
||||
checkArgument(
|
||||
isAdmin || registrar.isRegistryLockAllowed(),
|
||||
"Registry lock not allowed for this registrar");
|
||||
"Registry lock not allowed for registrar %s",
|
||||
clientId);
|
||||
return registrar;
|
||||
}
|
||||
|
||||
private ImmutableMap<String, ?> getLockedDomainsMap(String clientId)
|
||||
throws RegistrarAccessDeniedException {
|
||||
// Note: admins always have access to the locks page
|
||||
checkArgument(authResult.userAuthInfo().isPresent(), "User auth info must be present");
|
||||
|
||||
boolean isAdmin = registrarAccessor.isAdmin();
|
||||
Registrar registrar = getRegistrarAndVerifyLockAccess(registrarAccessor, clientId, isAdmin);
|
||||
User user = authResult.userAuthInfo().get().user();
|
||||
|
||||
Optional<RegistrarContact> contactOptional = getContactMatchingLogin(user, registrar);
|
||||
boolean isRegistryLockAllowed =
|
||||
isAdmin || contactOptional.map(RegistrarContact::isRegistryLockAllowed).orElse(false);
|
||||
// Use the contact email if it's present, else use the login email
|
||||
String relevantEmail =
|
||||
contactOptional.map(RegistrarContact::getEmailAddress).orElse(user.getEmail());
|
||||
return ImmutableMap.of(
|
||||
LOCK_ENABLED_FOR_CONTACT_PARAM,
|
||||
isRegistryLockAllowed,
|
||||
EMAIL_PARAM,
|
||||
relevantEmail,
|
||||
PARAM_CLIENT_ID,
|
||||
registrar.getClientId(),
|
||||
LOCKS_PARAM,
|
||||
getLockedDomains(clientId, isAdmin));
|
||||
}
|
||||
|
||||
private ImmutableList<ImmutableMap<String, ?>> getLockedDomains(
|
||||
String clientId, boolean isAdmin) {
|
||||
return jpaTm()
|
||||
|
||||
+22
-18
@@ -20,8 +20,11 @@ import static google.registry.persistence.transaction.TransactionManagerFactory.
|
||||
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.ui.server.registrar.RegistryLockGetAction.getContactMatchingLogin;
|
||||
import static google.registry.ui.server.registrar.RegistryLockGetAction.getRegistrarAndVerifyLockAccess;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import com.google.appengine.api.users.User;
|
||||
import com.google.common.base.Strings;
|
||||
import com.google.common.base.Throwables;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
@@ -124,11 +127,7 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
|
||||
.userAuthInfo()
|
||||
.orElseThrow(() -> new ForbiddenException("User is not logged in"));
|
||||
|
||||
boolean isAdmin = userAuthInfo.isUserAdmin();
|
||||
String userEmail = userAuthInfo.user().getEmail();
|
||||
if (!isAdmin) {
|
||||
verifyRegistryLockPassword(postInput, userEmail);
|
||||
}
|
||||
String userEmail = verifyPasswordAndGetEmail(userAuthInfo, postInput);
|
||||
jpaTm()
|
||||
.transact(
|
||||
() -> {
|
||||
@@ -138,9 +137,11 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
|
||||
postInput.fullyQualifiedDomainName,
|
||||
postInput.clientId,
|
||||
userEmail,
|
||||
isAdmin)
|
||||
registrarAccessor.isAdmin())
|
||||
: domainLockUtils.saveNewRegistryUnlockRequest(
|
||||
postInput.fullyQualifiedDomainName, postInput.clientId, isAdmin);
|
||||
postInput.fullyQualifiedDomainName,
|
||||
postInput.clientId,
|
||||
registrarAccessor.isAdmin());
|
||||
sendVerificationEmail(registryLock, userEmail, postInput.isLock);
|
||||
});
|
||||
String action = postInput.isLock ? "lock" : "unlock";
|
||||
@@ -180,25 +181,28 @@ public class RegistryLockPostAction implements Runnable, JsonActionRunner.JsonAc
|
||||
}
|
||||
}
|
||||
|
||||
private void verifyRegistryLockPassword(RegistryLockPostInput postInput, String userEmail)
|
||||
private String verifyPasswordAndGetEmail(
|
||||
UserAuthInfo userAuthInfo, RegistryLockPostInput postInput)
|
||||
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");
|
||||
User user = userAuthInfo.user();
|
||||
if (registrarAccessor.isAdmin()) {
|
||||
return user.getEmail();
|
||||
}
|
||||
// Verify that the user can access the registrar, that the user has
|
||||
// registry lock enabled, and that the user providjed a correct password
|
||||
Registrar registrar =
|
||||
getRegistrarAndVerifyLockAccess(registrarAccessor, postInput.clientId, false);
|
||||
RegistrarContact registrarContact =
|
||||
registrar.getContacts().stream()
|
||||
.filter(contact -> contact.getEmailAddress().equals(userEmail))
|
||||
.findFirst()
|
||||
getContactMatchingLogin(user, registrar)
|
||||
.orElseThrow(
|
||||
() ->
|
||||
new IllegalArgumentException(
|
||||
String.format("Unknown user email %s", userEmail)));
|
||||
String.format(
|
||||
"Cannot match user %s to registrar contact", user.getUserId())));
|
||||
checkArgument(
|
||||
registrarContact.verifyRegistryLockPassword(postInput.password),
|
||||
"Incorrect registry lock password for contact");
|
||||
return registrarContact.getEmailAddress();
|
||||
}
|
||||
|
||||
/** Value class that represents the expected input body from the UI request. */
|
||||
|
||||
@@ -38,6 +38,7 @@
|
||||
<class>google.registry.persistence.converter.CreateAutoTimestampConverter</class>
|
||||
<class>google.registry.persistence.converter.CurrencyUnitConverter</class>
|
||||
<class>google.registry.persistence.converter.DateTimeConverter</class>
|
||||
<class>google.registry.persistence.converter.DurationConverter</class>
|
||||
<class>google.registry.persistence.converter.RegistrarPocSetConverter</class>
|
||||
<class>google.registry.persistence.converter.StatusValueSetConverter</class>
|
||||
<class>google.registry.persistence.converter.StringListConverter</class>
|
||||
|
||||
@@ -0,0 +1,176 @@
|
||||
// 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.batch;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.model.eppcommon.StatusValue.PENDING_DELETE;
|
||||
import static google.registry.model.eppcommon.StatusValue.PENDING_TRANSFER;
|
||||
import static google.registry.model.ofy.ObjectifyService.ofy;
|
||||
import static google.registry.testing.DatastoreHelper.createTlds;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainBase;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatastoreHelper.persistDomainAsDeleted;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.SqlHelper.getMostRecentVerifiedRegistryLockByRepoId;
|
||||
import static google.registry.testing.SqlHelper.getRegistryLockByVerificationCode;
|
||||
import static google.registry.testing.SqlHelper.saveRegistryLock;
|
||||
import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STATUSES;
|
||||
import static javax.servlet.http.HttpServletResponse.SC_NO_CONTENT;
|
||||
|
||||
import com.google.common.collect.ImmutableSet;
|
||||
import google.registry.model.domain.DomainBase;
|
||||
import google.registry.model.host.HostResource;
|
||||
import google.registry.schema.domain.RegistryLock;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.DeterministicStringGenerator;
|
||||
import google.registry.testing.FakeClock;
|
||||
import google.registry.testing.FakeResponse;
|
||||
import google.registry.testing.UserInfo;
|
||||
import google.registry.tools.DomainLockUtils;
|
||||
import google.registry.util.StringGenerator.Alphabets;
|
||||
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 RelockDomainAction}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class RelockDomainActionTest {
|
||||
|
||||
private static final String DOMAIN_NAME = "example.tld";
|
||||
private static final String CLIENT_ID = "TheRegistrar";
|
||||
private static final String POC_ID = "marla.singer@example.com";
|
||||
|
||||
private final FakeResponse response = new FakeResponse();
|
||||
private final FakeClock clock = new FakeClock();
|
||||
private final DomainLockUtils domainLockUtils =
|
||||
new DomainLockUtils(new DeterministicStringGenerator(Alphabets.BASE_58));
|
||||
|
||||
@Rule
|
||||
public final AppEngineRule appEngineRule =
|
||||
AppEngineRule.builder()
|
||||
.withDatastoreAndCloudSql()
|
||||
.withUserService(UserInfo.create(POC_ID, "12345"))
|
||||
.build();
|
||||
|
||||
private DomainBase domain;
|
||||
private RegistryLock oldLock;
|
||||
private RelockDomainAction action;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
createTlds("tld", "net");
|
||||
HostResource host = persistActiveHost("ns1.example.net");
|
||||
domain = persistResource(newDomainBase(DOMAIN_NAME, host));
|
||||
|
||||
oldLock = domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, CLIENT_ID, POC_ID, false);
|
||||
assertThat(reloadDomain(domain).getStatusValues())
|
||||
.containsAtLeastElementsIn(REGISTRY_LOCK_STATUSES);
|
||||
oldLock = domainLockUtils.administrativelyApplyUnlock(DOMAIN_NAME, CLIENT_ID, false);
|
||||
assertThat(reloadDomain(domain).getStatusValues()).containsNoneIn(REGISTRY_LOCK_STATUSES);
|
||||
action = createAction(oldLock.getRevisionId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLock() {
|
||||
action.run();
|
||||
assertThat(reloadDomain(domain).getStatusValues())
|
||||
.containsAtLeastElementsIn(REGISTRY_LOCK_STATUSES);
|
||||
|
||||
// the old lock should have a reference to the relock
|
||||
RegistryLock newLock = getMostRecentVerifiedRegistryLockByRepoId(domain.getRepoId()).get();
|
||||
assertThat(getRegistryLockByVerificationCode(oldLock.getVerificationCode()).get().getRelock())
|
||||
.isEqualTo(newLock);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unknownCode() {
|
||||
action = createAction(12128675309L);
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
|
||||
assertThat(response.getPayload()).isEqualTo("Relock failed: Unknown revision ID 12128675309");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_pendingDelete() {
|
||||
persistResource(domain.asBuilder().setStatusValues(ImmutableSet.of(PENDING_DELETE)).build());
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo(String.format("Relock failed: Domain %s has a pending delete", DOMAIN_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_pendingTransfer() {
|
||||
persistResource(domain.asBuilder().setStatusValues(ImmutableSet.of(PENDING_TRANSFER)).build());
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo(String.format("Relock failed: Domain %s has a pending transfer", DOMAIN_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainAlreadyLocked() {
|
||||
domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, CLIENT_ID, null, true);
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo("Domain example.tld is already manually relocked, skipping automated relock.");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainDeleted() {
|
||||
persistDomainAsDeleted(domain, clock.nowUtc());
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo(String.format("Relock failed: Domain %s has been deleted", DOMAIN_NAME));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_domainTransferred() {
|
||||
persistResource(domain.asBuilder().setPersistedCurrentSponsorClientId("NewRegistrar").build());
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo(
|
||||
String.format(
|
||||
"Relock failed: Domain %s has been transferred from registrar %s to registrar "
|
||||
+ "%s since the unlock",
|
||||
DOMAIN_NAME, CLIENT_ID, "NewRegistrar"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_relockAlreadySet() {
|
||||
RegistryLock newLock =
|
||||
domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, CLIENT_ID, null, true);
|
||||
saveRegistryLock(oldLock.asBuilder().setRelock(newLock).build());
|
||||
// Save the domain without the lock statuses so that we pass that check in the action
|
||||
persistResource(domain.asBuilder().setStatusValues(ImmutableSet.of()).build());
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_NO_CONTENT);
|
||||
assertThat(response.getPayload())
|
||||
.isEqualTo("Domain example.tld is already manually relocked, skipping automated relock.");
|
||||
}
|
||||
|
||||
private DomainBase reloadDomain(DomainBase domain) {
|
||||
return ofy().load().entity(domain).now();
|
||||
}
|
||||
|
||||
private RelockDomainAction createAction(Long oldUnlockRevisionId) {
|
||||
return new RelockDomainAction(oldUnlockRevisionId, domainLockUtils, response);
|
||||
}
|
||||
}
|
||||
@@ -18,7 +18,9 @@ import static com.google.common.collect.ImmutableSet.toImmutableSet;
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
import static google.registry.testing.SqlHelper.getMostRecentRegistryLockByRepoId;
|
||||
import static google.registry.testing.SqlHelper.getMostRecentUnlockedRegistryLockByRepoId;
|
||||
import static google.registry.testing.SqlHelper.getMostRecentVerifiedRegistryLockByRepoId;
|
||||
import static google.registry.testing.SqlHelper.getRegistryLockByRevisionId;
|
||||
import static google.registry.testing.SqlHelper.getRegistryLockByVerificationCode;
|
||||
import static google.registry.testing.SqlHelper.getRegistryLocksByRegistrarId;
|
||||
import static google.registry.testing.SqlHelper.saveRegistryLock;
|
||||
@@ -28,6 +30,7 @@ import google.registry.schema.domain.RegistryLock;
|
||||
import google.registry.testing.AppEngineRule;
|
||||
import google.registry.testing.FakeClock;
|
||||
import java.util.Optional;
|
||||
import org.joda.time.Duration;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
import org.junit.runner.RunWith;
|
||||
@@ -86,12 +89,14 @@ public final class RegistryLockDaoTest {
|
||||
.setLockCompletionTimestamp(fakeClock.nowUtc())
|
||||
.setUnlockRequestTimestamp(fakeClock.nowUtc())
|
||||
.setUnlockCompletionTimestamp(fakeClock.nowUtc())
|
||||
.setRelockDuration(Duration.standardHours(6))
|
||||
.build());
|
||||
RegistryLock fromDatabase = getRegistryLockByVerificationCode(lock.getVerificationCode()).get();
|
||||
assertThat(fromDatabase.getUnlockRequestTimestamp()).isEqualTo(Optional.of(fakeClock.nowUtc()));
|
||||
assertThat(fromDatabase.getUnlockCompletionTimestamp())
|
||||
.isEqualTo(Optional.of(fakeClock.nowUtc()));
|
||||
assertThat(fromDatabase.isLocked()).isFalse();
|
||||
assertThat(fromDatabase.getRelockDuration().get()).isEqualTo(Duration.standardHours(6));
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -121,6 +126,20 @@ public final class RegistryLockDaoTest {
|
||||
assertThat(getRegistryLockByVerificationCode("hi").isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByRevisionId_valid() {
|
||||
RegistryLock lock = saveRegistryLock(createLock());
|
||||
RegistryLock otherLock = getRegistryLockByRevisionId(lock.getRevisionId()).get();
|
||||
// can't do direct comparison due to update time
|
||||
assertThat(lock.getDomainName()).isEqualTo(otherLock.getDomainName());
|
||||
assertThat(lock.getVerificationCode()).isEqualTo(otherLock.getVerificationCode());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testByRevisionId_invalid() {
|
||||
assertThat(getRegistryLockByRevisionId(8675309L).isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoad_lockedDomains_byRegistrarId() {
|
||||
RegistryLock lock = createLock();
|
||||
@@ -192,6 +211,30 @@ public final class RegistryLockDaoTest {
|
||||
assertThat(mostRecent.isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoad_verifiedUnlock_byRepoId() {
|
||||
RegistryLock lock =
|
||||
saveRegistryLock(
|
||||
createLock()
|
||||
.asBuilder()
|
||||
.setLockCompletionTimestamp(fakeClock.nowUtc())
|
||||
.setUnlockRequestTimestamp(fakeClock.nowUtc())
|
||||
.setUnlockCompletionTimestamp(fakeClock.nowUtc())
|
||||
.build());
|
||||
|
||||
Optional<RegistryLock> mostRecent = getMostRecentUnlockedRegistryLockByRepoId(lock.getRepoId());
|
||||
assertThat(mostRecent.get().getRevisionId()).isEqualTo(lock.getRevisionId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testLoad_verifiedUnlock_empty() {
|
||||
RegistryLock completedLock =
|
||||
createLock().asBuilder().setLockCompletionTimestamp(fakeClock.nowUtc()).build();
|
||||
saveRegistryLock(completedLock);
|
||||
assertThat(getMostRecentUnlockedRegistryLockByRepoId(completedLock.getRepoId()).isPresent())
|
||||
.isFalse();
|
||||
}
|
||||
|
||||
private RegistryLock createLock() {
|
||||
return new RegistryLock.Builder()
|
||||
.setRepoId("repoId")
|
||||
|
||||
+1
@@ -11,6 +11,7 @@
|
||||
// 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.converter;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
@@ -0,0 +1,80 @@
|
||||
// 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.converter;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
import static google.registry.persistence.transaction.TransactionManagerFactory.jpaTm;
|
||||
|
||||
import google.registry.model.ImmutableObject;
|
||||
import google.registry.persistence.transaction.JpaTestRules;
|
||||
import google.registry.persistence.transaction.JpaTestRules.JpaUnitTestRule;
|
||||
import java.math.BigInteger;
|
||||
import javax.persistence.Entity;
|
||||
import javax.persistence.Id;
|
||||
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 DurationConverter}. */
|
||||
@RunWith(JUnit4.class)
|
||||
public class DurationConverterTest {
|
||||
|
||||
@Rule
|
||||
public final JpaUnitTestRule jpaRule =
|
||||
new JpaTestRules.Builder().withEntityClass(TestEntity.class).buildUnitTestRule();
|
||||
|
||||
private final DurationConverter converter = new DurationConverter();
|
||||
|
||||
@Test
|
||||
public void testNulls() {
|
||||
assertThat(converter.convertToDatabaseColumn(null)).isNull();
|
||||
assertThat(converter.convertToEntityAttribute(null)).isNull();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testRoundTrip() {
|
||||
TestEntity entity = new TestEntity(Duration.standardDays(6));
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().persist(entity));
|
||||
assertThat(
|
||||
jpaTm()
|
||||
.transact(
|
||||
() ->
|
||||
jpaTm()
|
||||
.getEntityManager()
|
||||
.createNativeQuery(
|
||||
"SELECT duration FROM \"TestEntity\" WHERE name = 'id'")
|
||||
.getResultList()))
|
||||
.containsExactly(BigInteger.valueOf(Duration.standardDays(6).getMillis()));
|
||||
TestEntity persisted =
|
||||
jpaTm().transact(() -> jpaTm().getEntityManager().find(TestEntity.class, "id"));
|
||||
assertThat(persisted.duration).isEqualTo(Duration.standardDays(6));
|
||||
}
|
||||
|
||||
@Entity(name = "TestEntity") // Override entity name to avoid the nested class reference.
|
||||
public static class TestEntity extends ImmutableObject {
|
||||
|
||||
@Id String name = "id";
|
||||
|
||||
Duration duration;
|
||||
|
||||
public TestEntity() {}
|
||||
|
||||
TestEntity(Duration duration) {
|
||||
this.duration = duration;
|
||||
}
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -43,11 +43,11 @@ public class JpaTransactionManagerImplTest {
|
||||
|
||||
private final FakeClock fakeClock = new FakeClock();
|
||||
private final TestEntity theEntity = new TestEntity("theEntity", "foo");
|
||||
private final VKey<TestEntity> theEntityKey = VKey.create(TestEntity.class, "theEntity");
|
||||
private final VKey<TestEntity> theEntityKey = VKey.createSql(TestEntity.class, "theEntity");
|
||||
private final TestCompoundIdEntity compoundIdEntity =
|
||||
new TestCompoundIdEntity("compoundIdEntity", 10, "foo");
|
||||
private final VKey<TestCompoundIdEntity> compoundIdEntityKey =
|
||||
VKey.create(TestCompoundIdEntity.class, new CompoundId("compoundIdEntity", 10));
|
||||
VKey.createSql(TestCompoundIdEntity.class, new CompoundId("compoundIdEntity", 10));
|
||||
private final ImmutableList<TestEntity> moreEntities =
|
||||
ImmutableList.of(
|
||||
new TestEntity("entity1", "foo"),
|
||||
@@ -225,7 +225,7 @@ public class JpaTransactionManagerImplTest {
|
||||
public void update_succeeds() {
|
||||
jpaTm().transact(() -> jpaTm().saveNew(theEntity));
|
||||
TestEntity persisted =
|
||||
jpaTm().transact(() -> jpaTm().load(VKey.create(TestEntity.class, "theEntity"))).get();
|
||||
jpaTm().transact(() -> jpaTm().load(VKey.createSql(TestEntity.class, "theEntity"))).get();
|
||||
assertThat(persisted.data).isEqualTo("foo");
|
||||
theEntity.data = "bar";
|
||||
jpaTm().transact(() -> jpaTm().update(theEntity));
|
||||
|
||||
+2
-2
@@ -133,12 +133,12 @@ abstract class JpaTransactionManagerRule extends ExternalResource {
|
||||
extraEntityClasses);
|
||||
JpaTransactionManagerImpl txnManager = new JpaTransactionManagerImpl(emf, clock);
|
||||
cachedTm = TransactionManagerFactory.jpaTm();
|
||||
TransactionManagerFactory.setJpaTmForTesting(txnManager);
|
||||
TransactionManagerFactory.setJpaTm(txnManager);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void after() {
|
||||
TransactionManagerFactory.setJpaTmForTesting(cachedTm);
|
||||
TransactionManagerFactory.setJpaTm(cachedTm);
|
||||
if (emf != null) {
|
||||
emf.close();
|
||||
emf = null;
|
||||
|
||||
@@ -32,7 +32,7 @@ import org.junit.runners.JUnit4;
|
||||
@RunWith(JUnit4.class)
|
||||
public class RegistrarDaoTest extends EntityTestCase {
|
||||
|
||||
private final VKey<Registrar> registrarKey = VKey.create(Registrar.class, "registrarId");
|
||||
private final VKey<Registrar> registrarKey = VKey.createSql(Registrar.class, "registrarId");
|
||||
|
||||
private Registrar testRegistrar;
|
||||
|
||||
|
||||
@@ -249,7 +249,7 @@ public final class AppEngineRule extends ExternalResource {
|
||||
.setEmailAddress("Marla.Singer@crr.com")
|
||||
.setPhoneNumber("+1.2128675309")
|
||||
.setTypes(ImmutableSet.of(RegistrarContact.Type.TECH))
|
||||
.setGaeUserId(THE_REGISTRAR_GAE_USER_ID)
|
||||
.setGaeUserId("12345")
|
||||
.setAllowedToSetRegistryLockPassword(true)
|
||||
.setRegistryLockPassword("hi")
|
||||
.build();
|
||||
|
||||
@@ -40,9 +40,17 @@ public class SqlHelper {
|
||||
return jpaTm().transact(() -> RegistryLockDao.getMostRecentVerifiedLockByRepoId(repoId));
|
||||
}
|
||||
|
||||
public static Optional<RegistryLock> getMostRecentUnlockedRegistryLockByRepoId(String repoId) {
|
||||
return jpaTm().transact(() -> RegistryLockDao.getMostRecentVerifiedUnlockByRepoId(repoId));
|
||||
}
|
||||
|
||||
public static ImmutableList<RegistryLock> getRegistryLocksByRegistrarId(String registrarId) {
|
||||
return jpaTm().transact(() -> RegistryLockDao.getLocksByRegistrarId(registrarId));
|
||||
}
|
||||
|
||||
public static Optional<RegistryLock> getRegistryLockByRevisionId(long revisionId) {
|
||||
return jpaTm().transact(() -> RegistryLockDao.getByRevisionId(revisionId));
|
||||
}
|
||||
|
||||
private SqlHelper() {}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ import static google.registry.testing.DatastoreHelper.getOnlyHistoryEntryOfType;
|
||||
import static google.registry.testing.DatastoreHelper.newDomainBase;
|
||||
import static google.registry.testing.DatastoreHelper.persistActiveHost;
|
||||
import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.SqlHelper.getRegistryLockByRevisionId;
|
||||
import static google.registry.testing.SqlHelper.getRegistryLockByVerificationCode;
|
||||
import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STATUSES;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
@@ -80,23 +81,26 @@ public final class DomainLockUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testSuccess_createLock() {
|
||||
domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
RegistryLock lock =
|
||||
domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
assertNoDomainChanges();
|
||||
assertThat(lock.getLockCompletionTimestamp().isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_createUnlock() {
|
||||
domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
RegistryLock lock =
|
||||
domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false);
|
||||
domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false);
|
||||
domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false);
|
||||
assertThat(lock.getUnlockCompletionTimestamp().isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_createUnlock_adminUnlockingAdmin() {
|
||||
domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", null, true);
|
||||
RegistryLock lock =
|
||||
domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", null, true);
|
||||
domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), true);
|
||||
domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", true);
|
||||
domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", true);
|
||||
assertThat(lock.getUnlockCompletionTimestamp().isPresent()).isFalse();
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -130,9 +134,7 @@ public final class DomainLockUtilsTest {
|
||||
|
||||
@Test
|
||||
public void testSuccess_applyUnlockDomain() {
|
||||
RegistryLock lock =
|
||||
domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
domainLockUtils.verifyAndApplyLock(lock.getVerificationCode(), false);
|
||||
domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
RegistryLock unlock =
|
||||
domainLockUtils.saveNewRegistryUnlockRequest(DOMAIN_NAME, "TheRegistrar", false);
|
||||
domainLockUtils.verifyAndApplyUnlock(unlock.getVerificationCode(), false);
|
||||
@@ -189,6 +191,31 @@ public final class DomainLockUtilsTest {
|
||||
verifyProperlyUnlockedDomain(true);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_regularLock_relockSet() {
|
||||
domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
RegistryLock oldLock =
|
||||
domainLockUtils.administrativelyApplyUnlock(DOMAIN_NAME, "TheRegistrar", false);
|
||||
RegistryLock newLock =
|
||||
domainLockUtils.saveNewRegistryLockRequest(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
newLock = domainLockUtils.verifyAndApplyLock(newLock.getVerificationCode(), false);
|
||||
assertThat(
|
||||
getRegistryLockByRevisionId(oldLock.getRevisionId()).get().getRelock().getRevisionId())
|
||||
.isEqualTo(newLock.getRevisionId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_administrativelyLock_relockSet() {
|
||||
domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
RegistryLock oldLock =
|
||||
domainLockUtils.administrativelyApplyUnlock(DOMAIN_NAME, "TheRegistrar", false);
|
||||
RegistryLock newLock =
|
||||
domainLockUtils.administrativelyApplyLock(DOMAIN_NAME, "TheRegistrar", POC_ID, false);
|
||||
assertThat(
|
||||
getRegistryLockByRevisionId(oldLock.getRevisionId()).get().getRelock().getRevisionId())
|
||||
.isEqualTo(newLock.getRevisionId());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_createUnlock_alreadyPendingUnlock() {
|
||||
RegistryLock lock =
|
||||
|
||||
@@ -52,7 +52,7 @@ public class UpdateRegistrarCommandTest extends CommandTestCase<UpdateRegistrarC
|
||||
assertThat(loadRegistrar("NewRegistrar").verifyPassword("some_password")).isTrue();
|
||||
assertThat(
|
||||
jpaTm()
|
||||
.transact(() -> jpaTm().load(VKey.create(Registrar.class, "NewRegistrar")))
|
||||
.transact(() -> jpaTm().load(VKey.createSql(Registrar.class, "NewRegistrar")))
|
||||
.get()
|
||||
.verifyPassword("some_password"))
|
||||
.isTrue();
|
||||
|
||||
+46
-16
@@ -31,6 +31,7 @@ import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
import com.google.common.collect.ImmutableSetMultimap;
|
||||
import com.google.gson.Gson;
|
||||
import google.registry.model.registrar.RegistrarContact;
|
||||
import google.registry.request.Action.Method;
|
||||
import google.registry.request.auth.AuthLevel;
|
||||
import google.registry.request.auth.AuthResult;
|
||||
@@ -67,14 +68,15 @@ public final class RegistryLockGetActionTest {
|
||||
@Rule public final MockitoRule mocks = MockitoJUnit.rule();
|
||||
|
||||
private final FakeResponse response = new FakeResponse();
|
||||
private final User user = new User("Marla.Singer@crr.com", "gmail.com", "12345");
|
||||
|
||||
private User user;
|
||||
private AuthResult authResult;
|
||||
private AuthenticatedRegistrarAccessor accessor;
|
||||
private RegistryLockGetAction action;
|
||||
|
||||
@Before
|
||||
public void setup() {
|
||||
user = userFromRegistrarContact(AppEngineRule.makeRegistrarContact3());
|
||||
fakeClock.setTo(DateTime.parse("2000-06-08T22:00:00.0Z"));
|
||||
authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
|
||||
accessor =
|
||||
@@ -186,10 +188,10 @@ public final class RegistryLockGetActionTest {
|
||||
"locks",
|
||||
ImmutableList.of(
|
||||
new ImmutableMap.Builder<>()
|
||||
.put("fullyQualifiedDomainName", "expiredunlock.test")
|
||||
.put("lockedTime", "2000-06-08T22:00:00.000Z")
|
||||
.put("lockedBy", "johndoe@theregistrar.com")
|
||||
.put("userCanUnlock", true)
|
||||
.put("fullyQualifiedDomainName", "adminexample.test")
|
||||
.put("lockedTime", "2000-06-09T22:00:00.001Z")
|
||||
.put("lockedBy", "admin")
|
||||
.put("userCanUnlock", false)
|
||||
.put("isLockPending", false)
|
||||
.put("isUnlockPending", false)
|
||||
.build(),
|
||||
@@ -202,19 +204,11 @@ public final class RegistryLockGetActionTest {
|
||||
.put("isUnlockPending", false)
|
||||
.build(),
|
||||
new ImmutableMap.Builder<>()
|
||||
.put("fullyQualifiedDomainName", "adminexample.test")
|
||||
.put("lockedTime", "2000-06-09T22:00:00.001Z")
|
||||
.put("lockedBy", "admin")
|
||||
.put("userCanUnlock", false)
|
||||
.put("isLockPending", false)
|
||||
.put("isUnlockPending", false)
|
||||
.build(),
|
||||
new ImmutableMap.Builder<>()
|
||||
.put("fullyQualifiedDomainName", "pending.test")
|
||||
.put("lockedTime", "")
|
||||
.put("fullyQualifiedDomainName", "expiredunlock.test")
|
||||
.put("lockedTime", "2000-06-08T22:00:00.000Z")
|
||||
.put("lockedBy", "johndoe@theregistrar.com")
|
||||
.put("userCanUnlock", true)
|
||||
.put("isLockPending", true)
|
||||
.put("isLockPending", false)
|
||||
.put("isUnlockPending", false)
|
||||
.build(),
|
||||
new ImmutableMap.Builder<>()
|
||||
@@ -224,6 +218,14 @@ public final class RegistryLockGetActionTest {
|
||||
.put("userCanUnlock", true)
|
||||
.put("isLockPending", false)
|
||||
.put("isUnlockPending", true)
|
||||
.build(),
|
||||
new ImmutableMap.Builder<>()
|
||||
.put("fullyQualifiedDomainName", "pending.test")
|
||||
.put("lockedTime", "")
|
||||
.put("lockedBy", "johndoe@theregistrar.com")
|
||||
.put("userCanUnlock", true)
|
||||
.put("isLockPending", true)
|
||||
.put("isUnlockPending", false)
|
||||
.build()))));
|
||||
}
|
||||
|
||||
@@ -309,6 +311,29 @@ public final class RegistryLockGetActionTest {
|
||||
ImmutableList.of())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_linkedToContactEmail() {
|
||||
// Even though the user is some.email@gmail.com the contact is still Marla Singer
|
||||
user = new User("some.email@gmail.com", "gmail.com", user.getUserId());
|
||||
authResult = AuthResult.create(AuthLevel.USER, UserAuthInfo.create(user, false));
|
||||
action =
|
||||
new RegistryLockGetAction(
|
||||
Method.GET, response, accessor, authResult, Optional.of("TheRegistrar"));
|
||||
action.run();
|
||||
assertThat(GSON.fromJson(response.getPayload(), Map.class).get("results"))
|
||||
.isEqualTo(
|
||||
ImmutableList.of(
|
||||
ImmutableMap.of(
|
||||
"lockEnabledForContact",
|
||||
true,
|
||||
"email",
|
||||
"Marla.Singer@crr.com",
|
||||
"clientId",
|
||||
"TheRegistrar",
|
||||
"locks",
|
||||
ImmutableList.of())));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_lockNotAllowedForRegistrar() {
|
||||
// The UI shouldn't be making requests where lock isn't enabled for this registrar
|
||||
@@ -337,4 +362,9 @@ public final class RegistryLockGetActionTest {
|
||||
action.run();
|
||||
assertThat(response.getStatus()).isEqualTo(SC_FORBIDDEN);
|
||||
}
|
||||
|
||||
static User userFromRegistrarContact(RegistrarContact registrarContact) {
|
||||
return new User(
|
||||
registrarContact.getEmailAddress(), "gmail.com", registrarContact.getGaeUserId());
|
||||
}
|
||||
}
|
||||
|
||||
+21
-8
@@ -23,6 +23,7 @@ import static google.registry.testing.DatastoreHelper.persistResource;
|
||||
import static google.registry.testing.SqlHelper.getRegistryLockByVerificationCode;
|
||||
import static google.registry.testing.SqlHelper.saveRegistryLock;
|
||||
import static google.registry.tools.LockOrUnlockDomainCommand.REGISTRY_LOCK_STATUSES;
|
||||
import static google.registry.ui.server.registrar.RegistryLockGetActionTest.userFromRegistrarContact;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.verifyNoMoreInteractions;
|
||||
|
||||
@@ -78,11 +79,8 @@ public final class RegistryLockPostActionTest {
|
||||
|
||||
@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 User userWithoutPermission;
|
||||
private User userWithLockPermission;
|
||||
|
||||
private InternetAddress outgoingAddress;
|
||||
private DomainBase domain;
|
||||
@@ -93,6 +91,8 @@ public final class RegistryLockPostActionTest {
|
||||
|
||||
@Before
|
||||
public void setup() throws Exception {
|
||||
userWithLockPermission = userFromRegistrarContact(AppEngineRule.makeRegistrarContact3());
|
||||
userWithoutPermission = userFromRegistrarContact(AppEngineRule.makeRegistrarContact2());
|
||||
createTld("tld");
|
||||
domain = persistResource(newDomainBase("example.tld"));
|
||||
outgoingAddress = new InternetAddress("domain-registry@example.com");
|
||||
@@ -133,6 +133,18 @@ public final class RegistryLockPostActionTest {
|
||||
assertSuccess(response, "unlock", "johndoe@theregistrar.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSuccess_linkedToContactEmail() throws Exception {
|
||||
// Even though the user is some.email@gmail.com the contact is still Marla Singer
|
||||
userWithLockPermission =
|
||||
new User("some.email@gmail.com", "gmail.com", userWithLockPermission.getUserId());
|
||||
action =
|
||||
createAction(
|
||||
AuthResult.create(AuthLevel.USER, UserAuthInfo.create(userWithLockPermission, false)));
|
||||
Map<String, ?> response = action.handleJsonRequest(lockRequest());
|
||||
assertSuccess(response, "lock", "Marla.Singer@crr.com");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testFailure_unlock_noLock() {
|
||||
persistResource(domain.asBuilder().setStatusValues(REGISTRY_LOCK_STATUSES).build());
|
||||
@@ -233,7 +245,7 @@ public final class RegistryLockPostActionTest {
|
||||
persistResource(
|
||||
loadRegistrar("TheRegistrar").asBuilder().setRegistryLockAllowed(false).build());
|
||||
Map<String, ?> response = action.handleJsonRequest(lockRequest());
|
||||
assertFailureWithMessage(response, "Registry lock not allowed for this registrar");
|
||||
assertFailureWithMessage(response, "Registry lock not allowed for registrar TheRegistrar");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -244,7 +256,7 @@ public final class RegistryLockPostActionTest {
|
||||
"clientId", "TheRegistrar",
|
||||
"fullyQualifiedDomainName", "example.tld",
|
||||
"isLock", true));
|
||||
assertFailureWithMessage(response, "Missing key for password");
|
||||
assertFailureWithMessage(response, "Incorrect registry lock password for contact");
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -386,9 +398,10 @@ public final class RegistryLockPostActionTest {
|
||||
}
|
||||
|
||||
private RegistryLockPostAction createAction(AuthResult authResult) {
|
||||
Role role = authResult.userAuthInfo().get().isUserAdmin() ? Role.ADMIN : Role.OWNER;
|
||||
AuthenticatedRegistrarAccessor registrarAccessor =
|
||||
AuthenticatedRegistrarAccessor.createForTesting(
|
||||
ImmutableSetMultimap.of("TheRegistrar", Role.OWNER, "NewRegistrar", Role.OWNER));
|
||||
ImmutableSetMultimap.of("TheRegistrar", role, "NewRegistrar", role));
|
||||
JsonActionRunner jsonActionRunner =
|
||||
new JsonActionRunner(ImmutableMap.of(), new JsonResponse(new ResponseImpl(mockResponse)));
|
||||
DomainLockUtils domainLockUtils =
|
||||
|
||||
@@ -60,7 +60,8 @@ public class RegistrarConsoleScreenshotTest extends WebDriverTestCase {
|
||||
route("/registry-lock-verify", FrontendServlet.class))
|
||||
.setFilters(ObjectifyFilter.class, OfyFilter.class)
|
||||
.setFixtures(BASIC)
|
||||
.setEmail("Marla.Singer@crr.com")
|
||||
.setEmail("Marla.Singer@crr.com") // from AppEngineRule.makeRegistrarContact3
|
||||
.setGaeUserId("12345") // from AppEngineRule.makeRegistrarContact3
|
||||
.build();
|
||||
|
||||
@Test
|
||||
@@ -452,11 +453,12 @@ public class RegistrarConsoleScreenshotTest extends WebDriverTestCase {
|
||||
createTld("tld");
|
||||
// expired unlock request
|
||||
DomainBase expiredUnlockRequestDomain = persistActiveDomain("expiredunlock.tld");
|
||||
saveRegistryLock(createRegistryLock(expiredUnlockRequestDomain)
|
||||
.asBuilder()
|
||||
.setLockCompletionTimestamp(START_OF_TIME.minusDays(1))
|
||||
.setUnlockRequestTimestamp(START_OF_TIME.minusDays(1))
|
||||
.build());
|
||||
saveRegistryLock(
|
||||
createRegistryLock(expiredUnlockRequestDomain)
|
||||
.asBuilder()
|
||||
.setLockCompletionTimestamp(START_OF_TIME.minusDays(1))
|
||||
.setUnlockRequestTimestamp(START_OF_TIME.minusDays(1))
|
||||
.build());
|
||||
DomainBase domain = persistActiveDomain("example.tld");
|
||||
saveRegistryLock(createRegistryLock(domain).asBuilder().isSuperuser(true).build());
|
||||
DomainBase otherDomain = persistActiveDomain("otherexample.tld");
|
||||
|
||||
@@ -19,6 +19,7 @@ import static com.google.common.base.Preconditions.checkNotNull;
|
||||
import static google.registry.testing.AppEngineRule.THE_REGISTRAR_GAE_USER_ID;
|
||||
import static google.registry.util.NetworkUtils.getExternalAddressOfLocalSystem;
|
||||
import static google.registry.util.NetworkUtils.pickUnusedPort;
|
||||
import static google.registry.util.PreconditionsUtils.checkArgumentNotNull;
|
||||
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.collect.ImmutableMap;
|
||||
@@ -32,6 +33,7 @@ import google.registry.testing.UserInfo;
|
||||
import java.net.URL;
|
||||
import java.net.UnknownHostException;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Optional;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.Callable;
|
||||
import java.util.concurrent.FutureTask;
|
||||
@@ -66,7 +68,8 @@ public final class TestServerRule extends ExternalResource {
|
||||
ImmutableList<Route> routes,
|
||||
ImmutableList<Class<? extends Filter>> filters,
|
||||
ImmutableList<Fixture> fixtures,
|
||||
String email) {
|
||||
String email,
|
||||
Optional<String> gaeUserId) {
|
||||
this.runfiles = runfiles;
|
||||
this.routes = routes;
|
||||
this.filters = filters;
|
||||
@@ -79,7 +82,8 @@ public final class TestServerRule extends ExternalResource {
|
||||
.withLocalModules()
|
||||
.withUrlFetch()
|
||||
.withTaskQueue()
|
||||
.withUserService(UserInfo.createAdmin(email, THE_REGISTRAR_GAE_USER_ID))
|
||||
.withUserService(
|
||||
UserInfo.createAdmin(email, gaeUserId.orElse(THE_REGISTRAR_GAE_USER_ID)))
|
||||
.build();
|
||||
}
|
||||
|
||||
@@ -149,8 +153,8 @@ public final class TestServerRule extends ExternalResource {
|
||||
/**
|
||||
* Runs arbitrary code inside server event loop thread.
|
||||
*
|
||||
* <p>You should use this method when you want to do things like change Datastore, because the
|
||||
* App Engine testing environment is thread-local.
|
||||
* <p>You should use this method when you want to do things like change Datastore, because the App
|
||||
* Engine testing environment is thread-local.
|
||||
*/
|
||||
public <T> T runInAppEngineEnvironment(Callable<T> callback) throws Throwable {
|
||||
FutureTask<T> job = new FutureTask<>(callback);
|
||||
@@ -211,7 +215,6 @@ public final class TestServerRule extends ExternalResource {
|
||||
*
|
||||
* <p>This builder has three required fields: {@link #setRunfiles}, {@link #setRoutes}, and {@link
|
||||
* #setFilters}.
|
||||
*
|
||||
*/
|
||||
public static final class Builder {
|
||||
private ImmutableMap<String, Path> runfiles;
|
||||
@@ -219,6 +222,7 @@ public final class TestServerRule extends ExternalResource {
|
||||
ImmutableList<Class<? extends Filter>> filters;
|
||||
private ImmutableList<Fixture> fixtures = ImmutableList.of();
|
||||
private String email;
|
||||
private Optional<String> gaeUserId = Optional.empty();
|
||||
|
||||
/** Sets the directories containing the static files for {@link TestServer}. */
|
||||
public Builder setRunfiles(ImmutableMap<String, Path> runfiles) {
|
||||
@@ -256,6 +260,13 @@ public final class TestServerRule extends ExternalResource {
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Optionally, sets the GAE user ID for the logged in user. */
|
||||
public Builder setGaeUserId(String gaeUserId) {
|
||||
this.gaeUserId =
|
||||
Optional.of(checkArgumentNotNull(gaeUserId, "Must specify a non-null GAE user ID"));
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Returns a new {@link TestServerRule} instance. */
|
||||
public TestServerRule build() {
|
||||
return new TestServerRule(
|
||||
@@ -263,7 +274,8 @@ public final class TestServerRule extends ExternalResource {
|
||||
checkNotNull(this.routes),
|
||||
checkNotNull(this.filters),
|
||||
checkNotNull(this.fixtures),
|
||||
checkNotNull(this.email));
|
||||
checkNotNull(this.email),
|
||||
this.gaeUserId);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ PATH CLASS METHOD
|
||||
/_dr/task/rdeStaging RdeStagingAction GET,POST n INTERNAL,API APP ADMIN
|
||||
/_dr/task/rdeUpload RdeUploadAction POST n INTERNAL,API APP ADMIN
|
||||
/_dr/task/refreshDnsOnHostRename RefreshDnsOnHostRenameAction GET n INTERNAL,API APP ADMIN
|
||||
/_dr/task/relockDomain RelockDomainAction POST y INTERNAL,API APP ADMIN
|
||||
/_dr/task/resaveAllEppResources ResaveAllEppResourcesAction GET n INTERNAL,API APP ADMIN
|
||||
/_dr/task/resaveEntity ResaveEntityAction POST n INTERNAL,API APP ADMIN
|
||||
/_dr/task/syncGroupMembers SyncGroupMembersAction POST n INTERNAL,API APP ADMIN
|
||||
|
||||
+1
-1
@@ -13,7 +13,7 @@ contacts:
|
||||
ADDED:
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Extra Terrestrial, emailAddress=etphonehome@example.com, phoneNumber=+1.2345678901, faxNumber=null, types=[ADMIN, BILLING, TECH, WHOIS], gaeUserId=null, visibleInWhoisAsAdmin=true, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false}
|
||||
REMOVED:
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Marla Singer, emailAddress=Marla.Singer@crr.com, phoneNumber=+1.2128675309, faxNumber=null, types=[TECH], gaeUserId=31337, visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false},
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Marla Singer, emailAddress=Marla.Singer@crr.com, phoneNumber=+1.2128675309, faxNumber=null, types=[TECH], gaeUserId=12345, visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false},
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=John Doe, emailAddress=johndoe@theregistrar.com, phoneNumber=+1.1234567890, faxNumber=null, types=[ADMIN], gaeUserId=31337, visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false},
|
||||
{parent=Key<?>(EntityGroupRoot("cross-tld")/Registrar("TheRegistrar")), name=Jian-Yang, emailAddress=jyang@bachman.accelerator, phoneNumber=+1.1234567890, faxNumber=null, types=[TECH], gaeUserId=null, visibleInWhoisAsAdmin=false, visibleInWhoisAsTech=false, visibleInDomainWhoisAsAbuse=false, allowedToSetRegistryLockPassword=false}
|
||||
FINAL CONTENTS:
|
||||
|
||||
BIN
Binary file not shown.
|
Before Width: | Height: | Size: 69 KiB After Width: | Height: | Size: 69 KiB |
+1
-1
@@ -31,7 +31,7 @@ Below are the steps to submit a schema change:
|
||||
|
||||
1. Make your changes to entity classes, remembering to add new ones to
|
||||
`core/src/main/resources/META-INF/persistence.xml` so they'll be picked up.
|
||||
2. Run the `nomulus generate_sql_schema` command to generate a new version of
|
||||
2. Run the `devTool generate_sql_schema` command to generate a new version of
|
||||
`db-schema.sql.generated`. The full command line to do this is:
|
||||
|
||||
`./gradlew devTool --args="-e localhost generate_sql_schema
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
-- 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.
|
||||
|
||||
ALTER TABLE "RegistryLock" ADD COLUMN relock_revision_id bigint;
|
||||
|
||||
ALTER TABLE IF EXISTS "RegistryLock"
|
||||
ADD CONSTRAINT FK2lhcwpxlnqijr96irylrh1707
|
||||
FOREIGN KEY (relock_revision_id)
|
||||
REFERENCES "RegistryLock";
|
||||
@@ -0,0 +1,15 @@
|
||||
-- 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.
|
||||
|
||||
ALTER TABLE "RegistryLock" ADD COLUMN relock_duration bigint;
|
||||
@@ -176,10 +176,12 @@
|
||||
lock_request_timestamp timestamptz not null,
|
||||
registrar_id text not null,
|
||||
registrar_poc_id text,
|
||||
relock_duration int8,
|
||||
repo_id text not null,
|
||||
unlock_completion_timestamp timestamptz,
|
||||
unlock_request_timestamp timestamptz,
|
||||
verification_code text not null,
|
||||
relock_revision_id int8,
|
||||
primary key (revision_id)
|
||||
);
|
||||
|
||||
@@ -224,6 +226,11 @@ create index reservedlist_name_idx on "ReservedList" (name);
|
||||
foreign key (revision_id)
|
||||
references "PremiumList";
|
||||
|
||||
alter table if exists "RegistryLock"
|
||||
add constraint FK2lhcwpxlnqijr96irylrh1707
|
||||
foreign key (relock_revision_id)
|
||||
references "RegistryLock";
|
||||
|
||||
alter table if exists "ReservedEntry"
|
||||
add constraint FKgq03rk0bt1hb915dnyvd3vnfc
|
||||
foreign key (revision_id)
|
||||
|
||||
@@ -261,7 +261,9 @@ CREATE TABLE public."RegistryLock" (
|
||||
verification_code text NOT NULL,
|
||||
unlock_request_timestamp timestamp with time zone,
|
||||
unlock_completion_timestamp timestamp with time zone,
|
||||
last_update_timestamp timestamp with time zone
|
||||
last_update_timestamp timestamp with time zone,
|
||||
relock_revision_id bigint,
|
||||
relock_duration bigint
|
||||
);
|
||||
|
||||
|
||||
@@ -543,6 +545,14 @@ CREATE INDEX registrarpoc_gae_user_id_idx ON public."RegistrarPoc" USING btree (
|
||||
CREATE INDEX reservedlist_name_idx ON public."ReservedList" USING btree (name);
|
||||
|
||||
|
||||
--
|
||||
-- Name: RegistryLock fk2lhcwpxlnqijr96irylrh1707; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
ALTER TABLE ONLY public."RegistryLock"
|
||||
ADD CONSTRAINT fk2lhcwpxlnqijr96irylrh1707 FOREIGN KEY (relock_revision_id) REFERENCES public."RegistryLock"(revision_id);
|
||||
|
||||
|
||||
--
|
||||
-- Name: ClaimsEntry fk6sc6at5hedffc0nhdcab6ivuq; Type: FK CONSTRAINT; Schema: public; Owner: -
|
||||
--
|
||||
|
||||
@@ -43,6 +43,7 @@ ext {
|
||||
'com.google.auto.value:auto-value-annotations:1.6.3',
|
||||
'com.google.auto.value:auto-value:1.6.3',
|
||||
'com.google.closure-stylesheets:closure-stylesheets:1.5.0',
|
||||
'com.google.cloud.sql:jdbc-socket-factory-core:1.0.12',
|
||||
'com.google.cloud.sql:postgres-socket-factory:1.0.12',
|
||||
'com.google.cloud:google-cloud-core:1.59.0',
|
||||
'com.google.cloud:google-cloud-storage:1.59.0',
|
||||
|
||||
Reference in New Issue
Block a user