Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 7 additions & 7 deletions docs/oauth-2.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ For instructions on setting up your credentials properly, see the
already have an access token, you can make a request in the following way:

```java
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.books.Books;
import com.google.auth.http.HttpCredentialsAdapter;
Expand All @@ -59,7 +59,7 @@ GoogleCredentials credentials =

Books books =
new Books.Builder(
GoogleNetHttpTransport.newTrustedTransport(),
Gnew NetHttpTransport(),
GsonFactory.getDefaultInstance(),
new HttpCredentialsAdapter(credentials))
.setApplicationName("BooksExample/1.0")
Expand All @@ -79,7 +79,7 @@ App Engine takes care of all of the details. You only specify the OAuth 2.0
scope you need.

```java
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.gson.GsonFactory;
import com.google.api.services.books.Books;
import com.google.appengine.api.appidentity.AppIdentityService;
Expand All @@ -99,7 +99,7 @@ GoogleCredentials credentials =

Books books =
new Books.Builder(
GoogleNetHttpTransport.newTrustedTransport(),
new NetHttpTransport(),
GsonFactory.getDefaultInstance(),
new HttpCredentialsAdapter(credentials))
.setApplicationName("BooksExample/1.0")
Expand Down Expand Up @@ -373,7 +373,7 @@ a private key downloaded from the [Google API Console][console].
For example, you can make a request in the following way:

```java
HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();
HttpTransport httpTransport = new NetHttpTransport();
JsonFactory jsonFactory = GsonFactory.getDefaultInstance();

//Build service account credential
Expand Down Expand Up @@ -405,12 +405,12 @@ additionally call [`GoogleCredential.Builder.setServiceAccountUser(String)`][set

This is the command-line authorization code flow described in [Using OAuth 2.0 for Installed Applications][oauth2-installed-app].

Example snippet from [plus-cmdline-sample][plus-sample]:
Example usage:

```java
public static void main(String[] args) {
try {
httpTransport = GoogleNetHttpTransport.newTrustedTransport();
httpTransport = new NetHttpTransport();
dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);
// authorization
Credential credential = authorize();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@

import com.google.api.client.util.SecurityUtils;
import com.google.common.annotations.VisibleForTesting;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.security.GeneralSecurityException;
Expand Down Expand Up @@ -69,21 +71,96 @@ public final class GoogleUtils {
}

/** Cached value for {@link #getCertificateTrustStore()}. */
static KeyStore certTrustStore;
@VisibleForTesting static KeyStore certTrustStore;

/** Name of bundled keystore. */
static final String BUNDLED_KEYSTORE = "google.p12";

/** Bundled keystore password. */
static final String BUNDLED_KEYSTORE_PASSWORD = "notasecret";

/** Default JDK cacerts file path relative to java.home. */
@VisibleForTesting
static String[] possibleJdkPaths = {
"lib/security/cacerts", // Java 9+
"jre/lib/security/cacerts" // Java 8 and earlier
};

/** Java home system property key. */
static final String JAVA_HOME_KEY = "java.home";

/** Default password for JDK cacerts file. */
static final String DEFAULT_CACERTS_PASSWORD = "changeit";

/**
* Loads the bundled google.p12 keystore containing trusted root certificates.
*
* @return the loaded keystore
*/
@VisibleForTesting
static KeyStore getBundledKeystore() throws IOException, GeneralSecurityException {
KeyStore ks = SecurityUtils.getPkcs12KeyStore();
InputStream is = GoogleUtils.class.getResourceAsStream(BUNDLED_KEYSTORE);
SecurityUtils.loadKeyStore(ks, is, BUNDLED_KEYSTORE_PASSWORD);
return ks;
}

/**
* Returns the key store for trusted root certificates to use for Google APIs.
* Loads the default JDK keystore (cacerts) containing trusted root certificates. Uses Java's
* system properties + known cert locations to locate the default trust store.
*
* @return the loaded keystore
*/
@VisibleForTesting
static KeyStore getJdkDefaultKeyStore() throws IOException, GeneralSecurityException {
KeyStore keyStore = SecurityUtils.getDefaultKeyStore();

// Find the default JDK cacerts location
String javaHome = System.getProperty(JAVA_HOME_KEY);

for (String path : possibleJdkPaths) {
File cacertsFile = new File(javaHome, path);
try (FileInputStream fis = new FileInputStream(cacertsFile)) {
keyStore.load(fis, DEFAULT_CACERTS_PASSWORD.toCharArray());
return keyStore;
} catch (IOException e) {
// File doesn't exist or can't be read, try next path
}
}

throw new IOException("Unable to load default JDK cacerts file");
}

/**
* Returns a keystore for trusted root certificates to use for Google APIs.
*
* <p>Value is cached, so subsequent access is fast.
*
* <p>This method first attempts to load the JDK default keystore. If that fails or is not
* available, it falls back to loading the bundled Google certificate store.
*
* @since 1.14
* @deprecated Depending on your build environment this method potentially can contain outdated
* certs if loading jdk default certs fails. Instead of getting trusted certs directly use an
* HttpTransport wrapper such as {@link <a
* href="https://docs.cloud.google.com/java/docs/reference/google-http-client/latest/com.google.api.client.http.javanet.NetHttpTransport">NetHttpTransport</a>}
* which uses java jdk internal classes to load default jdk certs specifically for a build
* environment. If you need to access the keystore directly please create your own keystore
* file.
*/
@Deprecated
public static synchronized KeyStore getCertificateTrustStore()
throws IOException, GeneralSecurityException {
if (certTrustStore == null) {
certTrustStore = SecurityUtils.getPkcs12KeyStore();
InputStream keyStoreStream = GoogleUtils.class.getResourceAsStream("google.p12");
SecurityUtils.loadKeyStore(certTrustStore, keyStoreStream, "notasecret");
try {
certTrustStore = getJdkDefaultKeyStore();
} catch (Exception e) {
// If unable to retrieve default JDK keystore, fall through to bundled certificates
}

if (certTrustStore == null) {
certTrustStore = getBundledKeystore();
}
}
return certTrustStore;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,10 @@
*
* @since 1.14
* @author Yaniv Inbar
* @deprecated This legacy HttpTransport implementation is no longer being maintained.
* Please use {@link <a href="https://docs.cloud.google.com/java/docs/reference/google-http-client/latest/com.google.api.client.http.javanet.NetHttpTransport">NetHttpTransport</a> instead.
*/
@Deprecated
public class GoogleNetHttpTransport {

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,9 @@

package com.google.api.client.googleapis;

import static org.junit.Assert.assertNotEquals;

import java.security.KeyStore;
import java.util.Enumeration;
import java.util.regex.Matcher;
import junit.framework.TestCase;

Expand All @@ -26,16 +27,43 @@
*/
public class GoogleUtilsTest extends TestCase {

public void testGetCertificateTrustStore() throws Exception {
public void testGetCertificateTrustStore_LoadsJdkDefaultFirst() throws Exception {
GoogleUtils.certTrustStore = null;
KeyStore trustStore = GoogleUtils.getCertificateTrustStore();

// Load bundled keystore to compare
KeyStore bundled = GoogleUtils.getBundledKeystore();

assertNotEquals(
"Certificate truststore should NOT contain the same amount of certificates as the bundled keystore",
bundled.size(),
trustStore.size());
}

public void testGetCertificateTrustStore_LoadsBundledKeystoreIfJdkDefaultLoadFails()
throws Exception {
GoogleUtils.certTrustStore = null;
String[] originalPaths = GoogleUtils.possibleJdkPaths;
GoogleUtils.possibleJdkPaths = new String[0];

KeyStore trustStore = GoogleUtils.getCertificateTrustStore();
Enumeration<String> aliases = trustStore.aliases();
while (aliases.hasMoreElements()) {
String alias = aliases.nextElement();
assertTrue(trustStore.isCertificateEntry(alias));
}
// intentionally check the count of certificates, so it can help us detect if a new certificate
// has been added or removed
assertEquals(71, trustStore.size());

// Load bundled keystore to compare
KeyStore bundled = GoogleUtils.getBundledKeystore();
assertEquals(
"Certificate truststore should contain the same amount of certificates as the bundled keystore",
trustStore.size(),
bundled.size());

GoogleUtils.possibleJdkPaths = originalPaths;
}

public void testGetCertificateTrustStore_IsCached() throws Exception {
KeyStore trustStore1 = GoogleUtils.getCertificateTrustStore();
KeyStore trustStore2 = GoogleUtils.getCertificateTrustStore();

// Should return the exact same instance due to caching
assertSame("Trust store should be cached", trustStore1, trustStore2);
}

public void testVersionMatcher() {
Expand Down
Loading