1
0
mirror of https://github.com/google/nomulus synced 2026-01-08 23:23:32 +00:00

Make SecretManagerkeyring the only allowed keyring (#2636)

Remove the support for custom keyrings. There is no pressing use case,
and can be error-prone.
This commit is contained in:
Weimin Yu
2025-01-13 14:32:24 -05:00
committed by GitHub
parent 693467a165
commit f8407c74bc
19 changed files with 152 additions and 1072 deletions

View File

@@ -20,6 +20,7 @@ import dagger.Lazy;
import google.registry.config.CredentialModule;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.keyring.KeyringModule;
import google.registry.persistence.PersistenceModule;
import google.registry.persistence.PersistenceModule.BeamJpaTm;
import google.registry.persistence.PersistenceModule.BeamReadOnlyReplicaJpaTm;
@@ -36,6 +37,7 @@ import javax.inject.Singleton;
modules = {
ConfigModule.class,
CredentialModule.class,
KeyringModule.class,
PersistenceModule.class,
SecretManagerModule.class,
UtilsModule.class

View File

@@ -215,6 +215,7 @@ public class RegistryConfigSettings {
}
/** Configuration for keyrings (used to store secrets outside of source). */
// TODO(b/388835696): remove section after updating config files.
public static class Keyring {
public String activeKeyring;
}

View File

@@ -14,31 +14,22 @@
package google.registry.keyring;
import static com.google.common.base.Preconditions.checkState;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import google.registry.config.RegistryConfig.Config;
import google.registry.keyring.api.Keyring;
import java.util.Map;
import google.registry.keyring.secretmanager.SecretManagerKeyring;
import java.util.Optional;
import javax.inject.Singleton;
/** Dagger module for {@link Keyring} */
@Module
public final class KeyringModule {
public abstract class KeyringModule {
@Provides
@Binds
@Singleton
public static Keyring provideKeyring(
Map<String, Keyring> keyrings, @Config("activeKeyring") String activeKeyring) {
checkState(
keyrings.containsKey(activeKeyring),
"Invalid Keyring %s is configured; valid choices are %s",
activeKeyring,
keyrings.keySet());
return keyrings.get(activeKeyring);
}
public abstract Keyring provideKeyring(SecretManagerKeyring keyring);
@Provides
@Config("cloudSqlInstanceConnectionName")

View File

@@ -1,205 +0,0 @@
// Copyright 2017 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.keyring.api;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.MoreObjects;
import com.google.common.flogger.FluentLogger;
import google.registry.util.ComparingInvocationHandler;
import java.io.IOException;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Objects;
import javax.annotation.Nullable;
import org.bouncycastle.bcpg.BCPGKey;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
/**
* Checks that a second keyring returns the same result as the current one.
*
* <p>Will behave exactly like the "actualKeyring" - as in will throw / return the exact same values
* - no matter what the "secondKeyring" does. But will log a warning if "secondKeyring" acts
* differently than "actualKeyring".
*
* <p>If both keyrings threw exceptions, there is no check whether the exeptions are the same. The
* assumption is that an error happened in both, but they might report that error differently.
*/
public final class ComparatorKeyring extends ComparingInvocationHandler<Keyring> {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
private ComparatorKeyring(Keyring original, Keyring second) {
super(Keyring.class, original, second);
}
/**
* Returns an instance of Keyring that is an exact proxy of "original".
*
* <p>This proxy will log any differences in return value or thrown exceptions with "second".
*/
public static Keyring create(Keyring original, Keyring second) {
return new ComparatorKeyring(original, second).makeProxy();
}
@Override
protected void log(Method method, String message) {
logger.atSevere().log("ComparatorKeyring.%s: %s", method.getName(), message);
}
/** Implements equals for the PGP classes. */
@Override
protected boolean compareResults(Method method, @Nullable Object a, @Nullable Object b) {
Class<?> clazz = method.getReturnType();
if (PGPPublicKey.class.equals(clazz)) {
return compare((PGPPublicKey) a, (PGPPublicKey) b);
}
if (PGPPrivateKey.class.equals(clazz)) {
return compare((PGPPrivateKey) a, (PGPPrivateKey) b);
}
if (PGPKeyPair.class.equals(clazz)) {
return compare((PGPKeyPair) a, (PGPKeyPair) b);
}
return super.compareResults(method, a, b);
}
/** Implements toString for the PGP classes. */
@Override
protected String stringifyResult(Method method, @Nullable Object a) {
Class<?> clazz = method.getReturnType();
if (PGPPublicKey.class.equals(clazz)) {
return stringify((PGPPublicKey) a);
}
if (PGPPrivateKey.class.equals(clazz)) {
return stringify((PGPPrivateKey) a);
}
if (PGPKeyPair.class.equals(clazz)) {
return stringify((PGPKeyPair) a);
}
return super.stringifyResult(method, a);
}
@Override
protected String stringifyThrown(Method method, Throwable throwable) {
StringWriter stringWriter = new StringWriter();
PrintWriter printWriter = new PrintWriter(stringWriter);
throwable.printStackTrace(printWriter);
return String.format("%s\nStack trace:\n%s", throwable.toString(), stringWriter.toString());
}
// .equals implementation for PGP types.
@VisibleForTesting
static boolean compare(@Nullable PGPKeyPair a, @Nullable PGPKeyPair b) {
if (a == null || b == null) {
return a == null && b == null;
}
return compare(a.getPublicKey(), b.getPublicKey())
&& compare(a.getPrivateKey(), b.getPrivateKey());
}
@VisibleForTesting
static boolean compare(@Nullable PGPPublicKey a, @Nullable PGPPublicKey b) {
if (a == null || b == null) {
return a == null && b == null;
}
try {
return Arrays.equals(a.getFingerprint(), b.getFingerprint())
&& Arrays.equals(a.getEncoded(), b.getEncoded());
} catch (IOException e) {
logger.atSevere().withCause(e).log(
"ComparatorKeyring error: PGPPublicKey.getEncoded failed.");
return false;
}
}
@VisibleForTesting
static boolean compare(@Nullable PGPPrivateKey a, @Nullable PGPPrivateKey b) {
if (a == null || b == null) {
return a == null && b == null;
}
return a.getKeyID() == b.getKeyID()
&& compare(a.getPrivateKeyDataPacket(), b.getPrivateKeyDataPacket())
&& compare(a.getPublicKeyPacket(), b.getPublicKeyPacket());
}
@VisibleForTesting
static boolean compare(PublicKeyPacket a, PublicKeyPacket b) {
if (a == null || b == null) {
return a == null && b == null;
}
try {
return Arrays.equals(a.getEncoded(), b.getEncoded());
} catch (IOException e) {
logger.atSevere().withCause(e).log(
"ComparatorKeyring error: PublicKeyPacket.getEncoded failed.");
return false;
}
}
@VisibleForTesting
static boolean compare(BCPGKey a, BCPGKey b) {
if (a == null || b == null) {
return a == null && b == null;
}
return Objects.equals(a.getFormat(), b.getFormat())
&& Arrays.equals(a.getEncoded(), b.getEncoded());
}
// toString implementations
@VisibleForTesting
static String stringify(PGPKeyPair a) {
if (a == null) {
return "null";
}
return MoreObjects.toStringHelper(PGPKeyPair.class)
.addValue(stringify(a.getPublicKey()))
.addValue(stringify(a.getPrivateKey()))
.toString();
}
@VisibleForTesting
static String stringify(PGPPublicKey a) {
if (a == null) {
return "null";
}
StringBuilder builder = new StringBuilder();
for (byte b : a.getFingerprint()) {
builder.append(String.format("%02x:", b));
}
return MoreObjects.toStringHelper(PGPPublicKey.class)
.add("fingerprint", builder.toString())
.toString();
}
@VisibleForTesting
static String stringify(PGPPrivateKey a) {
if (a == null) {
return "null";
}
// We need to be careful what information we output here. The private key should be private, and
// I'm not sure what is safe to put in the logs.
return MoreObjects.toStringHelper(PGPPrivateKey.class)
.add("keyId", a.getKeyID())
.toString();
}
}

View File

@@ -1,133 +0,0 @@
// Copyright 2017 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.keyring.api;
import static com.google.common.io.Resources.getResource;
import static google.registry.keyring.api.PgpHelper.KeyRequirement.ENCRYPT_SIGN;
import static google.registry.keyring.api.PgpHelper.lookupKeyPair;
import com.google.common.base.VerifyException;
import com.google.common.io.ByteSource;
import com.google.common.io.Resources;
import dagger.Binds;
import dagger.Module;
import dagger.Provides;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
import java.io.IOException;
import java.io.InputStream;
import javax.annotation.concurrent.Immutable;
import javax.inject.Named;
import org.bouncycastle.openpgp.PGPException;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.PGPSecretKeyRingCollection;
import org.bouncycastle.openpgp.PGPUtil;
import org.bouncycastle.openpgp.bc.BcPGPPublicKeyRingCollection;
import org.bouncycastle.openpgp.bc.BcPGPSecretKeyRingCollection;
/**
* Dagger keyring module that provides an {@link InMemoryKeyring} instance populated with dummy
* values.
*
* <p>This dummy module allows the domain registry code to compile and run in an unmodified state,
* with all attempted outgoing connections failing because the supplied dummy credentials aren't
* valid. For a real system that needs to connect with external services, you should replace this
* module with one that loads real credentials from secure sources.
*
* <p>The dummy PGP keyrings are created using gnupg1/pgp1 roughly like the following (using
* gnupg2/pgp2 is an exercise left for the developer):
*
* <pre>{@code
* # mkdir gpg
* # chmod 700 gpg
* # gpg1 --homedir gpg --gen-key <<<EOF
* 1
* 1024
* 0
* Y
* Test Registry
* test-registry@example.com
*
* O
* EOF
* [press enter twice at keyring password prompts]
* # gpg1 --homedir gpg -a -o pgp-public-keyring.asc --export test-registry@example.com
* # gpg1 --homedir gpg -a -o pgp-private-keyring.asc --export-secret-keys test-registry@example.com
* # mv pgp*keyring.asc java/google/registry/keyring/api
* # rm -rf gpg
* }</pre>
*/
@Module
@Immutable
public abstract class DummyKeyringModule {
public static final String NAME = "Dummy";
/** The contents of a dummy PGP public key stored in a file. */
private static final ByteSource PGP_PUBLIC_KEYRING =
Resources.asByteSource(getResource(InMemoryKeyring.class, "pgp-public-keyring.asc"));
/** The contents of a dummy PGP private key stored in a file. */
private static final ByteSource PGP_PRIVATE_KEYRING =
Resources.asByteSource(getResource(InMemoryKeyring.class, "pgp-private-keyring.asc"));
/** The email address of the aforementioned PGP key. */
private static final String EMAIL_ADDRESS = "test-registry@example.com";
@Binds
@IntoMap
@StringKey(NAME)
abstract Keyring provideKeyring(@Named("DummyKeyring") InMemoryKeyring keyring);
/** Always returns a {@link InMemoryKeyring} instance. */
@Provides
@Named("DummyKeyring")
static InMemoryKeyring provideDummyKeyring() {
PGPKeyPair dummyKey;
try (InputStream publicInput = PGP_PUBLIC_KEYRING.openStream();
InputStream privateInput = PGP_PRIVATE_KEYRING.openStream()) {
PGPPublicKeyRingCollection publicKeys =
new BcPGPPublicKeyRingCollection(PGPUtil.getDecoderStream(publicInput));
PGPSecretKeyRingCollection privateKeys =
new BcPGPSecretKeyRingCollection(PGPUtil.getDecoderStream(privateInput));
dummyKey = lookupKeyPair(publicKeys, privateKeys, EMAIL_ADDRESS, ENCRYPT_SIGN);
} catch (PGPException | IOException e) {
throw new VerifyException("Failed to load PGP keys from jar", e);
}
// Use the same dummy PGP keypair for all required PGP keys -- a real production system would
// have different values for these keys. Pass dummy values for all Strings.
return new InMemoryKeyring(
dummyKey,
dummyKey,
dummyKey.getPublicKey(),
dummyKey,
dummyKey.getPublicKey(),
"not a real key",
"not a real key",
"not a real password",
"not a real API key",
"not a real login",
"not a real password",
"not a real login",
"not a real credential",
"not a real password",
"not a real password",
"not the real primary connection",
"not the real replica connection");
}
private DummyKeyringModule() {}
}

View File

@@ -1,175 +0,0 @@
// Copyright 2017 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.keyring.api;
import static com.google.common.base.Preconditions.checkArgument;
import static com.google.common.base.Preconditions.checkNotNull;
import javax.annotation.concurrent.Immutable;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
/** A {@link Keyring} that uses in-memory values for all credentials. */
@Immutable
public final class InMemoryKeyring implements Keyring {
private final PGPKeyPair rdeStagingKey;
private final PGPKeyPair rdeSigningKey;
private final PGPPublicKey rdeReceiverKey;
private final PGPKeyPair brdaSigningKey;
private final PGPPublicKey brdaEncryptionKey;
private final String rdeSshClientPublicKey;
private final String rdeSshClientPrivateKey;
private final String icannReportingPassword;
private final String safeBrowsingAPIKey;
private final String marksdbDnlLoginAndPassword;
private final String marksdbLordnPassword;
private final String marksdbSmdrlLoginAndPassword;
private final String bsaApiKey;
private final String sqlPrimaryConnectionName;
private final String sqlReplicaConnectionName;
public InMemoryKeyring(
PGPKeyPair rdeStagingKey,
PGPKeyPair rdeSigningKey,
PGPPublicKey rdeReceiverKey,
PGPKeyPair brdaSigningKey,
PGPPublicKey brdaEncryptionKey,
String rdeSshClientPublicKey,
String rdeSshClientPrivateKey,
String icannReportingPassword,
String safeBrowsingAPIKey,
String marksdbDnlLoginAndPassword,
String marksdbLordnPassword,
String marksdbSmdrlLoginAndPassword,
String cloudSqlPassword,
String toolsCloudSqlPassword,
String bsaApiKey,
String sqlPrimaryConnectionName,
String sqlReplicaConnectionName) {
checkArgument(PgpHelper.isSigningKey(rdeSigningKey.getPublicKey()),
"RDE signing key must support signing: %s", rdeSigningKey.getKeyID());
checkArgument(rdeStagingKey.getPublicKey().isEncryptionKey(),
"staging key must support encryption: %s", rdeStagingKey.getKeyID());
checkArgument(rdeReceiverKey.isEncryptionKey(),
"receiver key must support encryption: %s", rdeReceiverKey.getKeyID());
checkArgument(PgpHelper.isSigningKey(brdaSigningKey.getPublicKey()),
"BRDA signing key must support signing: %s", brdaSigningKey.getKeyID());
checkArgument(brdaEncryptionKey.isEncryptionKey(),
"encryption key must support encryption: %s", brdaEncryptionKey.getKeyID());
this.rdeStagingKey = rdeStagingKey;
this.rdeSigningKey = rdeSigningKey;
this.rdeReceiverKey = rdeReceiverKey;
this.brdaSigningKey = brdaSigningKey;
this.brdaEncryptionKey = brdaEncryptionKey;
this.rdeSshClientPublicKey = checkNotNull(rdeSshClientPublicKey, "rdeSshClientPublicKey");
this.rdeSshClientPrivateKey = checkNotNull(rdeSshClientPrivateKey, "rdeSshClientPrivateKey");
this.icannReportingPassword = checkNotNull(icannReportingPassword, "icannReportingPassword");
this.safeBrowsingAPIKey = checkNotNull(safeBrowsingAPIKey, "safeBrowsingAPIKey");
this.marksdbDnlLoginAndPassword =
checkNotNull(marksdbDnlLoginAndPassword, "marksdbDnlLoginAndPassword");
this.marksdbLordnPassword = checkNotNull(marksdbLordnPassword, "marksdbLordnPassword");
this.marksdbSmdrlLoginAndPassword =
checkNotNull(marksdbSmdrlLoginAndPassword, "marksdbSmdrlLoginAndPassword");
this.bsaApiKey = checkNotNull(bsaApiKey, "bsaApiKey");
this.sqlPrimaryConnectionName = sqlPrimaryConnectionName;
this.sqlReplicaConnectionName = sqlReplicaConnectionName;
}
@Override
public PGPKeyPair getRdeSigningKey() {
return rdeSigningKey;
}
@Override
public PGPPublicKey getRdeStagingEncryptionKey() {
return rdeStagingKey.getPublicKey();
}
@Override
public PGPPrivateKey getRdeStagingDecryptionKey() {
return rdeStagingKey.getPrivateKey();
}
@Override
public PGPPublicKey getRdeReceiverKey() {
return rdeReceiverKey;
}
@Override
public PGPKeyPair getBrdaSigningKey() {
return brdaSigningKey;
}
@Override
public PGPPublicKey getBrdaReceiverKey() {
return brdaEncryptionKey;
}
@Override
public String getRdeSshClientPublicKey() {
return rdeSshClientPublicKey;
}
@Override
public String getRdeSshClientPrivateKey() {
return rdeSshClientPrivateKey;
}
@Override
public String getIcannReportingPassword() {
return icannReportingPassword;
}
@Override
public String getSafeBrowsingAPIKey() {
return safeBrowsingAPIKey;
}
@Override
public String getMarksdbDnlLoginAndPassword() {
return marksdbDnlLoginAndPassword;
}
@Override
public String getMarksdbLordnPassword() {
return marksdbLordnPassword;
}
@Override
public String getMarksdbSmdrlLoginAndPassword() {
return marksdbSmdrlLoginAndPassword;
}
@Override
public String getBsaApiKey() {
return bsaApiKey;
}
@Override
public String getSqlPrimaryConnectionName() {
return sqlPrimaryConnectionName;
}
@Override
public String getSqlReplicaConnectionName() {
return sqlReplicaConnectionName;
}
/** Does nothing. */
@Override
public void close() {}
}

View File

@@ -1,40 +0,0 @@
// Copyright 2017 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.keyring.secretmanager;
import dagger.Binds;
import dagger.Module;
import dagger.multibindings.IntoMap;
import dagger.multibindings.StringKey;
import google.registry.keyring.api.Keyring;
/** Dagger module for {@link Keyring} backed by the Cloud SecretManager. */
@Module
public abstract class SecretManagerKeyringModule {
public static final String NAME = "CSM";
// TODO(b/257276342): Remove after configs in nomulus-internal are updated.
public static final String DEPRECATED_NAME = "KMS";
@Binds
@IntoMap
@StringKey(DEPRECATED_NAME)
abstract Keyring provideDeprecatedKeyring(SecretManagerKeyring keyring);
@Binds
@IntoMap
@StringKey(NAME)
abstract Keyring provideKeyring(SecretManagerKeyring keyring);
}

View File

@@ -35,9 +35,7 @@ import google.registry.groups.GmailModule;
import google.registry.groups.GroupsModule;
import google.registry.groups.GroupssettingsModule;
import google.registry.keyring.KeyringModule;
import google.registry.keyring.api.DummyKeyringModule;
import google.registry.keyring.api.KeyModule;
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
import google.registry.module.RegistryComponent.RegistryModule;
import google.registry.module.RequestComponent.RequestComponentModule;
import google.registry.monitoring.whitebox.StackdriverModule;
@@ -69,7 +67,6 @@ import javax.inject.Singleton;
CustomLogicFactoryModule.class,
DirectoryModule.class,
DriveModule.class,
DummyKeyringModule.class,
GmailModule.class,
GroupsModule.class,
GroupssettingsModule.class,
@@ -81,7 +78,6 @@ import javax.inject.Singleton;
PersistenceModule.class,
RegistryModule.class,
RequestComponentModule.class,
SecretManagerKeyringModule.class,
SecretManagerModule.class,
ServerTridProviderModule.class,
SheetsServiceModule.class,

View File

@@ -32,9 +32,7 @@ import google.registry.groups.GmailModule;
import google.registry.groups.GroupsModule;
import google.registry.groups.GroupssettingsModule;
import google.registry.keyring.KeyringModule;
import google.registry.keyring.api.DummyKeyringModule;
import google.registry.keyring.api.KeyModule;
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
import google.registry.module.backend.BackendRequestComponent.BackendRequestComponentModule;
import google.registry.monitoring.whitebox.StackdriverModule;
import google.registry.persistence.PersistenceModule;
@@ -60,7 +58,6 @@ import javax.inject.Singleton;
CredentialModule.class,
CustomLogicFactoryModule.class,
DirectoryModule.class,
DummyKeyringModule.class,
DriveModule.class,
GmailModule.class,
GroupsModule.class,
@@ -71,7 +68,6 @@ import javax.inject.Singleton;
KeyringModule.class,
NetHttpTransportModule.class,
PersistenceModule.class,
SecretManagerKeyringModule.class,
SecretManagerModule.class,
ServerTridProviderModule.class,
SheetsServiceModule.class,

View File

@@ -21,7 +21,6 @@ import google.registry.config.CredentialModule;
import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.groups.GmailModule;
import google.registry.keyring.KeyringModule;
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
import google.registry.module.bsa.BsaRequestComponent.BsaRequestComponentModule;
import google.registry.monitoring.whitebox.StackdriverModule;
import google.registry.persistence.PersistenceModule;
@@ -43,7 +42,6 @@ import javax.inject.Singleton;
GsonModule.class,
PersistenceModule.class,
KeyringModule.class,
SecretManagerKeyringModule.class,
SecretManagerModule.class,
StackdriverModule.class,
UrlConnectionServiceModule.class,

View File

@@ -27,9 +27,7 @@ import google.registry.groups.GmailModule;
import google.registry.groups.GroupsModule;
import google.registry.groups.GroupssettingsModule;
import google.registry.keyring.KeyringModule;
import google.registry.keyring.api.DummyKeyringModule;
import google.registry.keyring.api.KeyModule;
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
import google.registry.module.frontend.FrontendRequestComponent.FrontendRequestComponentModule;
import google.registry.monitoring.whitebox.StackdriverModule;
import google.registry.privileges.secretmanager.SecretManagerModule;
@@ -52,7 +50,6 @@ import javax.inject.Singleton;
CustomLogicFactoryModule.class,
CloudTasksUtilsModule.class,
DirectoryModule.class,
DummyKeyringModule.class,
FrontendRequestComponentModule.class,
GmailModule.class,
GroupsModule.class,
@@ -61,7 +58,6 @@ import javax.inject.Singleton;
KeyModule.class,
KeyringModule.class,
NetHttpTransportModule.class,
SecretManagerKeyringModule.class,
SecretManagerModule.class,
ServerTridProviderModule.class,
StackdriverModule.class,

View File

@@ -25,9 +25,7 @@ import google.registry.groups.DirectoryModule;
import google.registry.groups.GroupsModule;
import google.registry.groups.GroupssettingsModule;
import google.registry.keyring.KeyringModule;
import google.registry.keyring.api.DummyKeyringModule;
import google.registry.keyring.api.KeyModule;
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
import google.registry.module.pubapi.PubApiRequestComponent.PubApiRequestComponentModule;
import google.registry.monitoring.whitebox.StackdriverModule;
import google.registry.persistence.PersistenceModule;
@@ -47,7 +45,6 @@ import javax.inject.Singleton;
CredentialModule.class,
CustomLogicFactoryModule.class,
DirectoryModule.class,
DummyKeyringModule.class,
GroupsModule.class,
GroupssettingsModule.class,
GsonModule.class,
@@ -56,7 +53,6 @@ import javax.inject.Singleton;
NetHttpTransportModule.class,
PersistenceModule.class,
PubApiRequestComponentModule.class,
SecretManagerKeyringModule.class,
SecretManagerModule.class,
ServerTridProviderModule.class,
StackdriverModule.class,

View File

@@ -27,9 +27,7 @@ import google.registry.groups.DirectoryModule;
import google.registry.groups.GroupsModule;
import google.registry.groups.GroupssettingsModule;
import google.registry.keyring.KeyringModule;
import google.registry.keyring.api.DummyKeyringModule;
import google.registry.keyring.api.KeyModule;
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
import google.registry.module.tools.ToolsRequestComponent.ToolsRequestComponentModule;
import google.registry.monitoring.whitebox.StackdriverModule;
import google.registry.privileges.secretmanager.SecretManagerModule;
@@ -49,7 +47,6 @@ import javax.inject.Singleton;
CustomLogicFactoryModule.class,
CloudTasksUtilsModule.class,
DirectoryModule.class,
DummyKeyringModule.class,
DriveModule.class,
GroupsModule.class,
GroupssettingsModule.class,
@@ -57,7 +54,6 @@ import javax.inject.Singleton;
KeyModule.class,
KeyringModule.class,
NetHttpTransportModule.class,
SecretManagerKeyringModule.class,
SecretManagerModule.class,
ServerTridProviderModule.class,
StackdriverModule.class,

View File

@@ -17,7 +17,7 @@ package google.registry.persistence;
import dagger.Component;
import google.registry.config.CredentialModule;
import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
import google.registry.keyring.KeyringModule;
import google.registry.persistence.PersistenceModule.DefaultJpaTm;
import google.registry.persistence.PersistenceModule.ReadOnlyReplicaJpaTm;
import google.registry.persistence.transaction.JpaTransactionManager;
@@ -32,8 +32,8 @@ import javax.inject.Singleton;
modules = {
ConfigModule.class,
CredentialModule.class,
KeyringModule.class,
PersistenceModule.class,
SecretManagerKeyringModule.class,
SecretManagerModule.class,
UtilsModule.class
})

View File

@@ -34,14 +34,10 @@ import dagger.BindsOptionalOf;
import dagger.Module;
import dagger.Provides;
import google.registry.config.RegistryConfig.Config;
import google.registry.keyring.KeyringModule;
import google.registry.keyring.api.DummyKeyringModule;
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
import google.registry.persistence.transaction.CloudSqlCredentialSupplier;
import google.registry.persistence.transaction.JpaTransactionManager;
import google.registry.persistence.transaction.JpaTransactionManagerImpl;
import google.registry.persistence.transaction.TransactionManager;
import google.registry.privileges.secretmanager.SecretManagerModule;
import google.registry.privileges.secretmanager.SqlCredential;
import google.registry.privileges.secretmanager.SqlCredentialStore;
import google.registry.privileges.secretmanager.SqlUser;
@@ -67,14 +63,7 @@ import javax.inject.Singleton;
import org.hibernate.cfg.Environment;
/** Dagger module class for the persistence layer. */
// TODO(b/388835696): Use SecreteManagerKeyring in all environments and drop the `includes` below.
@Module(
includes = {
KeyringModule.class,
SecretManagerModule.class,
DummyKeyringModule.class,
SecretManagerKeyringModule.class
})
@Module
public abstract class PersistenceModule {
// This name must be the same as the one defined in persistence.xml.

View File

@@ -27,9 +27,7 @@ import google.registry.dns.writer.VoidDnsWriterModule;
import google.registry.dns.writer.clouddns.CloudDnsWriterModule;
import google.registry.dns.writer.dnsupdate.DnsUpdateWriterModule;
import google.registry.keyring.KeyringModule;
import google.registry.keyring.api.DummyKeyringModule;
import google.registry.keyring.api.KeyModule;
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
import google.registry.model.ModelModule;
import google.registry.persistence.PersistenceModule;
import google.registry.persistence.PersistenceModule.NomulusToolJpaTm;
@@ -60,7 +58,6 @@ import javax.inject.Singleton;
ConfigModule.class,
CloudDnsWriterModule.class,
CloudTasksUtilsModule.class,
DummyKeyringModule.class,
DnsUpdateWriterModule.class,
GsonModule.class,
KeyModule.class,
@@ -71,7 +68,6 @@ import javax.inject.Singleton;
RdeModule.class,
RegistryToolDataflowModule.class,
RequestFactoryModule.class,
SecretManagerKeyringModule.class,
SecretManagerModule.class,
UrlConnectionServiceModule.class,
UtilsModule.class,

View File

@@ -1,335 +0,0 @@
// Copyright 2017 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.keyring.api;
import static com.google.common.truth.Truth.assertThat;
import static google.registry.testing.LogsSubject.assertAboutLogs;
import static java.nio.charset.StandardCharsets.UTF_8;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import com.google.common.testing.TestLogHandler;
import google.registry.util.JdkLoggerConfig;
import java.io.IOException;
import java.util.logging.Level;
import org.bouncycastle.bcpg.BCPGKey;
import org.bouncycastle.bcpg.PublicKeyPacket;
import org.bouncycastle.openpgp.PGPKeyPair;
import org.bouncycastle.openpgp.PGPPrivateKey;
import org.bouncycastle.openpgp.PGPPublicKey;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
/** Unit tests for {@link ComparatorKeyring}. */
class ComparatorKeyringTest {
private static final String PUBLIC_KEY_FINGERPRINT = "fingerprint";
private static final String PUBLIC_KEY_TO_STRING =
"PGPPublicKey{fingerprint=66:69:6e:67:65:72:70:72:69:6e:74:}";
private static final String PRIVATE_KEY_TO_STRING =
"PGPPrivateKey{keyId=1}";
private static final String KEY_PAIR_TO_STRING =
String.format("PGPKeyPair{%s, %s}", PUBLIC_KEY_TO_STRING, PRIVATE_KEY_TO_STRING);
private static PGPPublicKey mockPublicKey(
boolean altFingerprint,
boolean altEncoded) throws IOException {
PGPPublicKey publicKey = mock(PGPPublicKey.class);
String fingerprint = altFingerprint ? "alternate" : PUBLIC_KEY_FINGERPRINT;
String encoded = altEncoded ? "alternate" : "publicKeyEncoded";
when(publicKey.getFingerprint()).thenReturn(fingerprint.getBytes(UTF_8));
when(publicKey.getEncoded()).thenReturn(encoded.getBytes(UTF_8));
return publicKey;
}
private static PGPPrivateKey mockPrivateKey(
boolean altId,
boolean altBcpgKeyFormat,
boolean altBcpgKeyEncoded,
boolean altPublicKeyPacketEncoded)
throws IOException {
String bcpgKeyFormat = altBcpgKeyFormat ? "alternate" : "bcpgFormat";
String bcpgKeyEncoded = altBcpgKeyEncoded ? "alternate" : "bcpgEncoded";
String publicKeyPacketEncoded = altPublicKeyPacketEncoded ? "alternate" : "packetEncoded";
BCPGKey bcpgKey = mock(BCPGKey.class);
PublicKeyPacket publicKeyPacket = mock(PublicKeyPacket.class);
when(bcpgKey.getFormat()).thenReturn(bcpgKeyFormat);
when(bcpgKey.getEncoded()).thenReturn(bcpgKeyEncoded.getBytes(UTF_8));
when(publicKeyPacket.getEncoded()).thenReturn(publicKeyPacketEncoded.getBytes(UTF_8));
return new PGPPrivateKey(altId ? 2 : 1, publicKeyPacket, bcpgKey);
}
private final TestLogHandler testLogHandler = new TestLogHandler();
@BeforeEach
void beforeEach() {
JdkLoggerConfig.getConfig(ComparatorKeyring.class).addHandler(testLogHandler);
}
@AfterEach
void afterEach() {
JdkLoggerConfig.getConfig(ComparatorKeyring.class).removeHandler(testLogHandler);
}
@Test
void testPublicKeyToString() throws Exception {
assertThat(
ComparatorKeyring.stringify(
mockPublicKey(false, false)))
.isEqualTo(PUBLIC_KEY_TO_STRING);
}
@Test
void testPublicKeyEquals() throws Exception {
assertThat(
ComparatorKeyring.compare(
mockPublicKey(false, false),
mockPublicKey(false, false)))
.isTrue();
}
@Test
void testPublicKeyDifferFingerprint_notEqual() throws Exception {
assertThat(
ComparatorKeyring.compare(
mockPublicKey(false, false),
mockPublicKey(true, false)))
.isFalse();
}
@Test
void testPublicKeyDifferEncoded_notEqual() throws Exception {
assertThat(
ComparatorKeyring.compare(
mockPublicKey(false, false),
mockPublicKey(false, true)))
.isFalse();
}
@Test
void testPrivateKeyToString() throws Exception {
assertThat(
ComparatorKeyring.stringify(
mockPrivateKey(false, false, false, false)))
.isEqualTo(PRIVATE_KEY_TO_STRING);
}
@Test
void testPrivateKeyEquals() throws Exception {
assertThat(
ComparatorKeyring.compare(
mockPrivateKey(false, false, false, false),
mockPrivateKey(false, false, false, false)))
.isTrue();
}
@Test
void testPrivateKeyDifferId_notEquals() throws Exception {
assertThat(
ComparatorKeyring.compare(
mockPrivateKey(false, false, false, false),
mockPrivateKey(true, false, false, false)))
.isFalse();
}
@Test
void testPrivateKeyDifferBcpgFormat_notEquals() throws Exception {
assertThat(
ComparatorKeyring.compare(
mockPrivateKey(false, false, false, false),
mockPrivateKey(false, true, false, false)))
.isFalse();
}
@Test
void testPrivateKeyDifferBcpgEncoding_notEquals() throws Exception {
assertThat(
ComparatorKeyring.compare(
mockPrivateKey(false, false, false, false),
mockPrivateKey(false, false, true, false)))
.isFalse();
}
@Test
void testPrivateKeyDifferPublicKeyEncoding_notEquals() throws Exception {
assertThat(
ComparatorKeyring.compare(
mockPrivateKey(false, false, false, false),
mockPrivateKey(false, false, false, true)))
.isFalse();
}
@Test
void testKeyPairToString() throws Exception {
assertThat(
ComparatorKeyring.stringify(
new PGPKeyPair(
mockPublicKey(false, false),
mockPrivateKey(false, false, false, false))))
.isEqualTo(KEY_PAIR_TO_STRING);
}
@Test
void testKeyPairEquals() throws Exception {
assertThat(
ComparatorKeyring.compare(
new PGPKeyPair(
mockPublicKey(false, false),
mockPrivateKey(false, false, false, false)),
new PGPKeyPair(
mockPublicKey(false, false),
mockPrivateKey(false, false, false, false))))
.isTrue();
}
@Test
void testKeyPairDifferPublicKey_notEqual() throws Exception {
assertThat(
ComparatorKeyring.compare(
new PGPKeyPair(
mockPublicKey(false, false),
mockPrivateKey(false, false, false, false)),
new PGPKeyPair(
mockPublicKey(true, false),
mockPrivateKey(false, false, false, false))))
.isFalse();
}
@Test
void testKeyPairDifferPrivateKey_notEqual() throws Exception {
assertThat(
ComparatorKeyring.compare(
new PGPKeyPair(
mockPublicKey(false, false),
mockPrivateKey(false, false, false, false)),
new PGPKeyPair(
mockPublicKey(false, false),
mockPrivateKey(true, false, false, false))))
.isFalse();
}
// We don't need to check every single method in the generated instance to see that it behaves
// correctly. This should have been tested in ComparatorGenerator.
//
// We will fully test a single method just to make sure everything is "connected" correctly.
@Test
void testRdeSigningKey_actualThrows() throws Exception {
Keyring actualKeyring = mock(Keyring.class);
Keyring secondKeyring = mock(Keyring.class);
PGPKeyPair keyPair =
new PGPKeyPair(
mockPublicKey(false, false),
mockPrivateKey(false, false, false, false));
when(actualKeyring.getRdeSigningKey()).thenThrow(new KeyringException("message"));
when(secondKeyring.getRdeSigningKey()).thenReturn(keyPair);
Keyring comparatorKeyring = ComparatorKeyring.create(actualKeyring, secondKeyring);
assertThrows(KeyringException.class, comparatorKeyring::getRdeSigningKey);
assertAboutLogs()
.that(testLogHandler)
.hasLogAtLevelWithMessage(
Level.SEVERE, ".getRdeSigningKey: Only actual implementation threw exception");
}
@Test
void testRdeSigningKey_secondThrows() throws Exception {
Keyring actualKeyring = mock(Keyring.class);
Keyring secondKeyring = mock(Keyring.class);
PGPKeyPair keyPair =
new PGPKeyPair(
mockPublicKey(false, false),
mockPrivateKey(false, false, false, false));
when(actualKeyring.getRdeSigningKey()).thenReturn(keyPair);
when(secondKeyring.getRdeSigningKey()).thenThrow(new KeyringException("message"));
Keyring comparatorKeyring = ComparatorKeyring.create(actualKeyring, secondKeyring);
assertThat(comparatorKeyring.getRdeSigningKey()).isSameInstanceAs(keyPair);
assertAboutLogs()
.that(testLogHandler)
.hasLogAtLevelWithMessage(
Level.SEVERE, ".getRdeSigningKey: Only second implementation threw exception");
}
@Test
void testRdeSigningKey_bothThrow() {
Keyring actualKeyring = mock(Keyring.class);
Keyring secondKeyring = mock(Keyring.class);
when(actualKeyring.getRdeSigningKey()).thenThrow(new KeyringException("message"));
when(secondKeyring.getRdeSigningKey()).thenThrow(new KeyringException("message"));
Keyring comparatorKeyring = ComparatorKeyring.create(actualKeyring, secondKeyring);
assertThrows(KeyringException.class, comparatorKeyring::getRdeSigningKey);
assertAboutLogs().that(testLogHandler).hasNoLogsAtLevel(Level.SEVERE);
}
@Test
void testRdeSigningKey_same() throws Exception {
Keyring actualKeyring = mock(Keyring.class);
Keyring secondKeyring = mock(Keyring.class);
PGPKeyPair keyPair =
new PGPKeyPair(
mockPublicKey(false, false),
mockPrivateKey(false, false, false, false));
PGPKeyPair keyPairCopy =
new PGPKeyPair(
mockPublicKey(false, false),
mockPrivateKey(false, false, false, false));
when(actualKeyring.getRdeSigningKey()).thenReturn(keyPair);
when(secondKeyring.getRdeSigningKey()).thenReturn(keyPairCopy);
Keyring comparatorKeyring = ComparatorKeyring.create(actualKeyring, secondKeyring);
assertThat(comparatorKeyring.getRdeSigningKey()).isSameInstanceAs(keyPair);
assertAboutLogs().that(testLogHandler).hasNoLogsAtLevel(Level.SEVERE);
}
@Test
void testRdeSigningKey_different() throws Exception {
Keyring actualKeyring = mock(Keyring.class);
Keyring secondKeyring = mock(Keyring.class);
PGPKeyPair keyPair =
new PGPKeyPair(
mockPublicKey(false, false),
mockPrivateKey(false, false, false, false));
PGPKeyPair keyPairDifferent =
new PGPKeyPair(
mockPublicKey(false, false),
mockPrivateKey(true, false, false, false));
when(actualKeyring.getRdeSigningKey()).thenReturn(keyPair);
when(secondKeyring.getRdeSigningKey()).thenReturn(keyPairDifferent);
Keyring comparatorKeyring = ComparatorKeyring.create(actualKeyring, secondKeyring);
assertThat(comparatorKeyring.getRdeSigningKey()).isSameInstanceAs(keyPair);
String alternateKeyPairString = String.format(
"PGPKeyPair{%s, %s}", PUBLIC_KEY_TO_STRING, "PGPPrivateKey{keyId=2}");
assertAboutLogs()
.that(testLogHandler)
.hasLogAtLevelWithMessage(
Level.SEVERE,
String.format(
".getRdeSigningKey: Got different results! '%s' vs '%s'",
KEY_PAIR_TO_STRING,
alternateKeyPairString));
}
}

View File

@@ -20,7 +20,6 @@ import dagger.Component;
import google.registry.config.CredentialModule;
import google.registry.config.RegistryConfig.Config;
import google.registry.config.RegistryConfig.ConfigModule;
import google.registry.keyring.secretmanager.SecretManagerKeyringModule;
import google.registry.persistence.PersistenceModule.TransactionIsolationLevel;
import google.registry.privileges.secretmanager.SecretManagerModule;
import google.registry.util.UtilsModule;
@@ -84,7 +83,6 @@ class PersistenceModuleTest {
ConfigModule.class,
CredentialModule.class,
PersistenceModule.class,
SecretManagerKeyringModule.class,
SecretManagerModule.class,
UtilsModule.class
})