|
16 | 16 |
|
17 | 17 | import com.google.api.client.util.SecurityUtils; |
18 | 18 | import com.google.common.annotations.VisibleForTesting; |
| 19 | +import java.io.File; |
| 20 | +import java.io.FileInputStream; |
19 | 21 | import java.io.IOException; |
20 | 22 | import java.io.InputStream; |
21 | 23 | import java.security.GeneralSecurityException; |
@@ -69,21 +71,87 @@ public final class GoogleUtils { |
69 | 71 | } |
70 | 72 |
|
71 | 73 | /** Cached value for {@link #getCertificateTrustStore()}. */ |
72 | | - static KeyStore certTrustStore; |
| 74 | + @VisibleForTesting static KeyStore certTrustStore; |
| 75 | + |
| 76 | + /** Name of bundled keystore. */ |
| 77 | + static final String BUNDLED_KEYSTORE = "google.p12"; |
| 78 | + |
| 79 | + /** Bundled keystore password. */ |
| 80 | + static final String BUNDLED_KEYSTORE_PASSWORD = "notasecret"; |
| 81 | + |
| 82 | + /** Default JDK cacerts file path relative to java.home. */ |
| 83 | + @VisibleForTesting |
| 84 | + static String[] possibleJdkPaths = {"lib/security/cacerts", "jre/lib/security/cacerts"}; |
| 85 | + |
| 86 | + /** Java home system property key. */ |
| 87 | + static final String JAVA_HOME_KEY = "java.home"; |
| 88 | + |
| 89 | + /** Default password for JDK cacerts file. */ |
| 90 | + static final String DEFAULT_CACERTS_PASSWORD = "changeit"; |
| 91 | + |
| 92 | + /** |
| 93 | + * Loads the bundled google.p12 keystore containing trusted root certificates. |
| 94 | + * |
| 95 | + * @return the loaded keystore |
| 96 | + */ |
| 97 | + @VisibleForTesting |
| 98 | + static KeyStore getBundledKeystore() throws IOException, GeneralSecurityException { |
| 99 | + KeyStore ks = SecurityUtils.getPkcs12KeyStore(); |
| 100 | + InputStream is = GoogleUtils.class.getResourceAsStream(BUNDLED_KEYSTORE); |
| 101 | + SecurityUtils.loadKeyStore(ks, is, BUNDLED_KEYSTORE_PASSWORD); |
| 102 | + return ks; |
| 103 | + } |
73 | 104 |
|
74 | 105 | /** |
75 | | - * Returns the key store for trusted root certificates to use for Google APIs. |
| 106 | + * Loads the default JDK keystore (cacerts) containing trusted root certificates. Uses Java's |
| 107 | + * system properties + known cert locations to locate the default trust store. |
| 108 | + * |
| 109 | + * @return the loaded keystore or null if unable to find/load keystore |
| 110 | + */ |
| 111 | + @VisibleForTesting |
| 112 | + static KeyStore getJdkDefaultKeyStore() throws IOException, GeneralSecurityException { |
| 113 | + KeyStore keyStore = SecurityUtils.getDefaultKeyStore(); |
| 114 | + |
| 115 | + // Find the default JDK cacerts location |
| 116 | + String javaHome = System.getProperty(JAVA_HOME_KEY); |
| 117 | + |
| 118 | + for (String path : possibleJdkPaths) { |
| 119 | + File cacertsFile = new File(javaHome, path); |
| 120 | + try (FileInputStream fis = new FileInputStream(cacertsFile)) { |
| 121 | + keyStore.load(fis, DEFAULT_CACERTS_PASSWORD.toCharArray()); |
| 122 | + return keyStore; |
| 123 | + } catch (IOException e) { |
| 124 | + // File doesn't exist or can't be read, try next path |
| 125 | + } |
| 126 | + } |
| 127 | + return null; |
| 128 | + } |
| 129 | + |
| 130 | + /** |
| 131 | + * Returns a keystore for trusted root certificates to use for Google APIs. |
76 | 132 | * |
77 | 133 | * <p>Value is cached, so subsequent access is fast. |
78 | 134 | * |
| 135 | + * <p>This method first attempts to load the JDK default keystore. If that fails or is not |
| 136 | + * available, it falls back to loading the bundled Google certificate store. |
| 137 | + * |
79 | 138 | * @since 1.14 |
| 139 | + * @deprecated Depending on your build environment this method potentially can contain outdated |
| 140 | + * certs if loading jdk default certs fails. Instead of getting trusted certs directly use an |
| 141 | + * HttpTransport wrapper such as {@link <a |
| 142 | + * href="https://docs.cloud.google.com/java/docs/reference/google-http-client/latest/com.google.api.client.http.javanet.NetHttpTransport">NetHttpTransport</a>} |
| 143 | + * which uses java jdk internal classes to load default jdk certs specifically for a build |
| 144 | + * environment. If you need to access the keystore directly please create your own keystore |
| 145 | + * file. |
80 | 146 | */ |
| 147 | + @Deprecated |
81 | 148 | public static synchronized KeyStore getCertificateTrustStore() |
82 | 149 | throws IOException, GeneralSecurityException { |
83 | 150 | if (certTrustStore == null) { |
84 | | - certTrustStore = SecurityUtils.getPkcs12KeyStore(); |
85 | | - InputStream keyStoreStream = GoogleUtils.class.getResourceAsStream("google.p12"); |
86 | | - SecurityUtils.loadKeyStore(certTrustStore, keyStoreStream, "notasecret"); |
| 151 | + certTrustStore = getJdkDefaultKeyStore(); |
| 152 | + if (certTrustStore == null) { |
| 153 | + certTrustStore = getBundledKeystore(); |
| 154 | + } |
87 | 155 | } |
88 | 156 | return certTrustStore; |
89 | 157 | } |
|
0 commit comments