Skip to content

Commit

Permalink
Use google-auth-library-oauth2-http to get default credentials (#151)
Browse files Browse the repository at this point in the history
  • Loading branch information
yhrn authored and kurtisvg committed Aug 5, 2019
1 parent fa165cf commit 23f977c
Show file tree
Hide file tree
Showing 4 changed files with 26 additions and 44 deletions.
6 changes: 6 additions & 0 deletions core/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,12 @@
<version>v1beta4-rev20190510-1.28.0</version>
</dependency>

<dependency>
<groupId>com.google.auth</groupId>
<artifactId>google-auth-library-oauth2-http</artifactId>
<version>0.16.2</version>
</dependency>

<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@
package com.google.cloud.sql;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.http.HttpRequestInitializer;

/** Factory for creating {@link Credential}s for interaction with Cloud SQL Admin API. */
public interface CredentialFactory {
/** Name of system property that can specify an alternative credential factory. */
String CREDENTIAL_FACTORY_PROPERTY = "cloudSql.socketFactory.credentialFactory";

Credential create();
HttpRequestInitializer create();
}
45 changes: 10 additions & 35 deletions core/src/main/java/com/google/cloud/sql/core/CoreSocketFactory.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,6 @@

package com.google.cloud.sql.core;

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpRequestInitializer;
import com.google.api.client.http.HttpTransport;
Expand All @@ -26,6 +24,8 @@
import com.google.api.services.sqladmin.SQLAdmin;
import com.google.api.services.sqladmin.SQLAdmin.Builder;
import com.google.api.services.sqladmin.SQLAdminScopes;
import com.google.auth.http.HttpCredentialsAdapter;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.cloud.sql.CredentialFactory;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
Expand All @@ -40,8 +40,6 @@
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
Expand All @@ -50,7 +48,6 @@
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.logging.Logger;
import javax.annotation.Nullable;
import javax.net.ssl.SSLSocket;
import jnr.unixsocket.UnixSocketAddress;
import jnr.unixsocket.UnixSocketChannel;
Expand Down Expand Up @@ -90,9 +87,7 @@ public final class CoreSocketFactory {

private static CoreSocketFactory coreSocketFactory;

private final CertificateFactory certificateFactory;
private final ListenableFuture<KeyPair> localKeyPair;
private final Credential credential;
private final ConcurrentHashMap<String, CloudSqlInstance> instances = new ConcurrentHashMap<>();
private final ListeningScheduledExecutorService executor;
private final SQLAdmin adminApi;
Expand All @@ -101,12 +96,9 @@ public final class CoreSocketFactory {
@VisibleForTesting
CoreSocketFactory(
ListenableFuture<KeyPair> localKeyPair,
Credential credential,
SQLAdmin adminApi,
int serverProxyPort,
ListeningScheduledExecutorService executor) {
this.certificateFactory = x509CertificateFactory();
this.credential = credential;
this.adminApi = adminApi;
this.serverProxyPort = serverProxyPort;
this.executor = executor;
Expand All @@ -131,30 +123,20 @@ public static synchronized CoreSocketFactory getInstance() {
credentialFactory = new ApplicationDefaultCredentialFactory();
}

Credential credential = credentialFactory.create();
HttpRequestInitializer credential = credentialFactory.create();
SQLAdmin adminApi = createAdminApiClient(credential);
ListeningScheduledExecutorService executor = getDefaultExecutor();

coreSocketFactory =
new CoreSocketFactory(
executor.submit(CoreSocketFactory::generateRsaKeyPair),
credential,
adminApi,
DEFAULT_SERVER_PROXY_PORT,
executor);
}
return coreSocketFactory;
}

// Returns a factory used to create X.509 public certificates
private static CertificateFactory x509CertificateFactory() {
try {
return CertificateFactory.getInstance("X.509");
} catch (CertificateException err) {
throw new RuntimeException("X509 implementation not available", err);
}
}

// TODO(kvg): Figure out better executor to use for testing
@VisibleForTesting
// Returns a listenable, scheduled executor that exits upon shutdown.
Expand Down Expand Up @@ -283,13 +265,6 @@ private static List<String> listIpTypes(String cloudSqlIpTypes) {
return result;
}

@Nullable
private String getCredentialServiceAccount(Credential credential) {
return credential instanceof GoogleCredential
? ((GoogleCredential) credential).getServiceAccountId()
: null;
}

private static SQLAdmin createAdminApiClient(HttpRequestInitializer requestInitializer) {
HttpTransport httpTransport;
try {
Expand Down Expand Up @@ -318,19 +293,19 @@ private static SQLAdmin createAdminApiClient(HttpRequestInitializer requestIniti

private static class ApplicationDefaultCredentialFactory implements CredentialFactory {
@Override
public Credential create() {
GoogleCredential credential;
public HttpRequestInitializer create() {
GoogleCredentials credentials;
try {
credential = GoogleCredential.getApplicationDefault();
credentials = GoogleCredentials.getApplicationDefault();
} catch (IOException err) {
throw new RuntimeException(
"Unable to obtain credentials to communicate with the Cloud SQL API", err);
}
if (credential.createScopedRequired()) {
credential =
credential.createScoped(Collections.singletonList(SQLAdminScopes.SQLSERVICE_ADMIN));
if (credentials.createScopedRequired()) {
credentials =
credentials.createScoped(Collections.singletonList(SQLAdminScopes.SQLSERVICE_ADMIN));
}
return credential;
return new HttpCredentialsAdapter(credentials);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -176,7 +176,7 @@ public void setup() throws IOException, GeneralSecurityException, ExecutionExcep
@Test
public void create_throwsErrorForInvalidInstanceName() throws IOException {
CoreSocketFactory coreSocketFactory =
new CoreSocketFactory(clientKeyPair, credential, adminApi, 3307, defaultExecutor);
new CoreSocketFactory(clientKeyPair, adminApi, 3307, defaultExecutor);
try {
coreSocketFactory.createSslSocket("myProject", Arrays.asList("PRIMARY"));
fail();
Expand All @@ -195,7 +195,7 @@ public void create_throwsErrorForInvalidInstanceName() throws IOException {
@Test
public void create_throwsErrorForInvalidInstanceRegion() throws IOException {
CoreSocketFactory coreSocketFactory =
new CoreSocketFactory(clientKeyPair, credential, adminApi, 3307, defaultExecutor);
new CoreSocketFactory(clientKeyPair, adminApi, 3307, defaultExecutor);
try {
coreSocketFactory.createSslSocket(
"myProject:notMyRegion:myInstance", Arrays.asList("PRIMARY"));
Expand All @@ -218,7 +218,7 @@ public void create_successfulPrivateConnection()
int port = sslServer.start(PRIVATE_IP);

CoreSocketFactory coreSocketFactory =
new CoreSocketFactory(clientKeyPair, credential, adminApi, port, defaultExecutor);
new CoreSocketFactory(clientKeyPair, adminApi, port, defaultExecutor);
Socket socket =
coreSocketFactory.createSslSocket(
"myProject:myRegion:myInstance", Arrays.asList("PRIVATE"));
Expand All @@ -240,7 +240,7 @@ public void create_successfulConnection() throws IOException, InterruptedExcepti
int port = sslServer.start();

CoreSocketFactory coreSocketFactory =
new CoreSocketFactory(clientKeyPair, credential, adminApi, port, defaultExecutor);
new CoreSocketFactory(clientKeyPair, adminApi, port, defaultExecutor);
Socket socket =
coreSocketFactory.createSslSocket(
"myProject:myRegion:myInstance", Arrays.asList("PRIMARY"));
Expand Down Expand Up @@ -272,7 +272,7 @@ public void create_expiredCertificateOnFirstConnection_certificateRenewed()
.thenReturn(new SslCert().setCert(createEphemeralCert(Duration.ofMinutes(65))));

CoreSocketFactory coreSocketFactory =
new CoreSocketFactory(clientKeyPair, credential, adminApi, port, defaultExecutor);
new CoreSocketFactory(clientKeyPair, adminApi, port, defaultExecutor);
Socket socket =
coreSocketFactory.createSslSocket(
"myProject:myRegion:myInstance", Arrays.asList("PRIMARY"));
Expand All @@ -294,7 +294,7 @@ public void create_certificateReusedIfNotExpired() throws IOException, Interrupt
int port = sslServer.start();

CoreSocketFactory coreSocketFactory =
new CoreSocketFactory(clientKeyPair, credential, adminApi, port, defaultExecutor);
new CoreSocketFactory(clientKeyPair, adminApi, port, defaultExecutor);
coreSocketFactory.createSslSocket("myProject:myRegion:myInstance", Arrays.asList("PRIMARY"));

verify(adminApiInstances).get("myProject", "myInstance");
Expand All @@ -311,7 +311,7 @@ public void create_certificateReusedIfNotExpired() throws IOException, Interrupt
@Test
public void create_adminApiNotEnabled() throws IOException {
CoreSocketFactory coreSocketFactory =
new CoreSocketFactory(clientKeyPair, credential, adminApi, 3307, defaultExecutor);
new CoreSocketFactory(clientKeyPair, adminApi, 3307, defaultExecutor);
try {
// Use a different project to get Api Not Enabled Error.
coreSocketFactory.createSslSocket(
Expand All @@ -331,7 +331,7 @@ public void create_adminApiNotEnabled() throws IOException {
@Test
public void create_notAuthorized() throws IOException {
CoreSocketFactory coreSocketFactory =
new CoreSocketFactory(clientKeyPair, credential, adminApi, 3307, defaultExecutor);
new CoreSocketFactory(clientKeyPair, adminApi, 3307, defaultExecutor);
try {
// Use a different instance to simulate incorrect permissions.
coreSocketFactory.createSslSocket(
Expand Down

0 comments on commit 23f977c

Please sign in to comment.