3131package com .google .auth .mtls ;
3232
3333import com .google .api .client .util .SecurityUtils ;
34+ import com .google .auth .oauth2 .EnvironmentProvider ;
35+ import com .google .auth .oauth2 .PropertyProvider ;
36+ import com .google .auth .oauth2 .SystemEnvironmentProvider ;
37+ import com .google .auth .oauth2 .SystemPropertyProvider ;
3438import com .google .common .base .Strings ;
3539import java .io .File ;
3640import java .io .FileInputStream ;
37- import java .io .FileNotFoundException ;
3841import java .io .IOException ;
3942import java .io .InputStream ;
4043import java .io .SequenceInputStream ;
4144import java .security .KeyStore ;
42- import java .util .Locale ;
4345
4446/**
4547 * This class implements {@link MtlsProvider} for the Google Auth library transport layer via {@link
4850 * backwards compatibility.
4951 */
5052public class X509Provider implements MtlsProvider {
51- static final String CERTIFICATE_CONFIGURATION_ENV_VARIABLE = "GOOGLE_API_CERTIFICATE_CONFIG" ;
52- static final String WELL_KNOWN_CERTIFICATE_CONFIG_FILE = "certificate_config.json" ;
53- static final String CLOUDSDK_CONFIG_DIRECTORY = "gcloud" ;
54-
53+ private final EnvironmentProvider envProvider ;
54+ private final PropertyProvider propProvider ;
5555 private final String certConfigPathOverride ;
5656
5757 /**
5858 * Creates an X509 provider with an override path for the certificate configuration, bypassing the
5959 * normal checks for the well known certificate configuration file path and environment variable.
6060 * This is meant for internal Google Cloud usage and behavior may be changed without warning.
6161 *
62+ * @param envProvider environment provider used for environment variables
63+ * @param propProvider property provider used for system properties
6264 * @param certConfigPathOverride the path to read the certificate configuration from.
6365 */
64- public X509Provider (String certConfigPathOverride ) {
66+ public X509Provider (
67+ EnvironmentProvider envProvider ,
68+ PropertyProvider propProvider ,
69+ String certConfigPathOverride ) {
70+ this .envProvider = envProvider ;
71+ this .propProvider = propProvider ;
6572 this .certConfigPathOverride = certConfigPathOverride ;
6673 }
6774
75+ /**
76+ * Creates an X509 provider with an override path for the certificate configuration.
77+ *
78+ * @param certConfigPathOverride the path to read the certificate configuration from.
79+ */
80+ public X509Provider (String certConfigPathOverride ) {
81+ this (
82+ SystemEnvironmentProvider .getInstance (),
83+ SystemPropertyProvider .getInstance (),
84+ certConfigPathOverride );
85+ }
86+
6887 /**
6988 * Creates a new X.509 provider that will check the environment variable path and the well known
7089 * Gcloud certificate configuration location. This is meant for internal Google Cloud usage and
@@ -78,23 +97,15 @@ public X509Provider() {
7897 * Returns the path to the client certificate file specified by the loaded workload certificate
7998 * configuration.
8099 *
81- * <p>If the configuration has not been loaded yet (e.g., if {@link #getKeyStore()} has not been
82- * called), this method will attempt to load it first by searching the override path, environment
83- * variable, and well-known locations.
100+ * <p>If the configuration has not been loaded yet, this method will attempt to load it first by
101+ * searching the override path, environment variable, and well-known locations.
84102 *
85103 * @return The path to the certificate file.
86104 * @throws IOException if the certificate configuration cannot be found or loaded, or if the
87105 * configuration file does not specify a certificate path.
88- * @throws CertificateSourceUnavailableException if the configuration file is not found.
89106 */
90107 public String getCertificatePath () throws IOException {
91- String certPath = getWorkloadCertificateConfiguration ().getCertPath ();
92- if (Strings .isNullOrEmpty (certPath )) {
93- // Ensure the loaded configuration actually contains the required path.
94- throw new CertificateSourceUnavailableException (
95- "Certificate configuration loaded successfully, but does not contain a 'certificate_file' path." );
96- }
97- return certPath ;
108+ return MtlsUtils .getCertificatePath (envProvider , propProvider , certConfigPathOverride );
98109 }
99110
100111 /**
@@ -115,12 +126,14 @@ public String getCertificatePath() throws IOException {
115126 */
116127 @ Override
117128 public KeyStore getKeyStore () throws CertificateSourceUnavailableException , IOException {
118- WorkloadCertificateConfiguration workloadCertConfig = getWorkloadCertificateConfiguration ();
129+ WorkloadCertificateConfiguration workloadCertConfig =
130+ MtlsUtils .getWorkloadCertificateConfiguration (
131+ envProvider , propProvider , certConfigPathOverride );
119132
120133 // Read the certificate and private key file paths into streams.
121- try (InputStream certStream = createInputStream (new File (workloadCertConfig .getCertPath ()));
134+ try (InputStream certStream = new FileInputStream (new File (workloadCertConfig .getCertPath ()));
122135 InputStream privateKeyStream =
123- createInputStream (new File (workloadCertConfig .getPrivateKeyPath ()));
136+ new FileInputStream (new File (workloadCertConfig .getPrivateKeyPath ()));
124137 SequenceInputStream certAndPrivateKeyStream =
125138 new SequenceInputStream (certStream , privateKeyStream )) {
126139
@@ -150,73 +163,5 @@ public boolean isAvailable() throws IOException {
150163 return true ;
151164 }
152165
153- private WorkloadCertificateConfiguration getWorkloadCertificateConfiguration ()
154- throws IOException {
155- File certConfig ;
156- if (this .certConfigPathOverride != null ) {
157- certConfig = new File (certConfigPathOverride );
158- } else {
159- String envCredentialsPath = getEnv (CERTIFICATE_CONFIGURATION_ENV_VARIABLE );
160- if (!Strings .isNullOrEmpty (envCredentialsPath )) {
161- certConfig = new File (envCredentialsPath );
162- } else {
163- certConfig = getWellKnownCertificateConfigFile ();
164- }
165- }
166- InputStream certConfigStream = null ;
167- try {
168- if (!isFile (certConfig )) {
169- // Path will be put in the message from the catch block below
170- throw new CertificateSourceUnavailableException ("File does not exist." );
171- }
172- certConfigStream = createInputStream (certConfig );
173- return WorkloadCertificateConfiguration .fromCertificateConfigurationStream (certConfigStream );
174- } finally {
175- if (certConfigStream != null ) {
176- certConfigStream .close ();
177- }
178- }
179- }
180166
181- /*
182- * Start of methods to allow overriding in the test code to isolate from the environment.
183- */
184- boolean isFile (File file ) {
185- return file .isFile ();
186- }
187-
188- InputStream createInputStream (File file ) throws FileNotFoundException {
189- return new FileInputStream (file );
190- }
191-
192- String getEnv (String name ) {
193- return System .getenv (name );
194- }
195-
196- String getOsName () {
197- return getProperty ("os.name" , "" ).toLowerCase (Locale .US );
198- }
199-
200- String getProperty (String property , String def ) {
201- return System .getProperty (property , def );
202- }
203-
204- /*
205- * End of methods to allow overriding in the test code to isolate from the environment.
206- */
207-
208- private File getWellKnownCertificateConfigFile () {
209- File cloudConfigPath ;
210- String envPath = getEnv ("CLOUDSDK_CONFIG" );
211- if (envPath != null ) {
212- cloudConfigPath = new File (envPath );
213- } else if (getOsName ().indexOf ("windows" ) >= 0 ) {
214- File appDataPath = new File (getEnv ("APPDATA" ));
215- cloudConfigPath = new File (appDataPath , CLOUDSDK_CONFIG_DIRECTORY );
216- } else {
217- File configPath = new File (getProperty ("user.home" , "" ), ".config" );
218- cloudConfigPath = new File (configPath , CLOUDSDK_CONFIG_DIRECTORY );
219- }
220- return new File (cloudConfigPath , WELL_KNOWN_CERTIFICATE_CONFIG_FILE );
221- }
222167}
0 commit comments