forked from googleapis/google-auth-library-java
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathX509Provider.java
More file actions
198 lines (180 loc) · 7.58 KB
/
X509Provider.java
File metadata and controls
198 lines (180 loc) · 7.58 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
/*
* Copyright 2025, Google Inc. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are
* met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above
* copyright notice, this list of conditions and the following disclaimer
* in the documentation and/or other materials provided with the
* distribution.
*
* * Neither the name of Google Inc. nor the names of its
* contributors may be used to endorse or promote products derived from
* this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
package com.google.auth.mtls;
import com.google.api.client.util.SecurityUtils;
import com.google.common.base.Strings;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.io.SequenceInputStream;
import java.security.KeyStore;
import java.util.Locale;
/**
* This class provides certificate key stores to the Google Auth library transport layer via
* certificate configuration files. This is only meant to be used internally to Google Cloud
* libraries, and the public facing methods may be changed without notice, and have no guarantee of
* backwards compatability.
*/
public class X509Provider {
static final String CERTIFICATE_CONFIGURATION_ENV_VARIABLE = "GOOGLE_API_CERTIFICATE_CONFIG";
static final String WELL_KNOWN_CERTIFICATE_CONFIG_FILE = "certificate_config.json";
static final String CLOUDSDK_CONFIG_DIRECTORY = "gcloud";
private String certConfigPathOverride;
/**
* Creates an X509 provider with an override path for the certificate configuration, bypassing the
* normal checks for the well known certificate configuration file path and environment variable.
* This is meant for internal Google Cloud usage and behavior may be changed without warning.
*
* @param certConfigPathOverride the path to read the certificate configuration from.
*/
public X509Provider(String certConfigPathOverride) {
this.certConfigPathOverride = certConfigPathOverride;
}
/**
* Creates a new X.509 provider that will check the environment variable path and the well known
* Gcloud certificate configuration location. This is meant for internal Google Cloud usage and
* behavior may be changed without warning.
*/
public X509Provider() {
this(null);
}
/**
* Finds the certificate configuration file, then builds a Keystore using the X.509 certificate
* and private key pointed to by the configuration. This will check the following locations in
* order.
*
* <ul>
* <li>The certificate config override path, if set.
* <li>The path pointed to by the "GOOGLE_API_CERTIFICATE_CONFIG" environment variable
* <li>The well known gcloud location for the certificate configuration file.
* </ul>
*
* @return a KeyStore containing the X.509 certificate specified by the certificate configuration.
* @throws IOException if there is an error retrieving the certificate configuration.
*/
public KeyStore getKeyStore() throws IOException {
WorkloadCertificateConfiguration workloadCertConfig = getWorkloadCertificateConfiguration();
InputStream certStream = null;
InputStream privateKeyStream = null;
SequenceInputStream certAndPrivateKeyStream = null;
try {
// Read the certificate and private key file paths into separate streams.
File certFile = new File(workloadCertConfig.getCertPath());
File privateKeyFile = new File(workloadCertConfig.getPrivateKeyPath());
certStream = createInputStream(certFile);
privateKeyStream = createInputStream(privateKeyFile);
// Merge the two streams into a single stream.
certAndPrivateKeyStream = new SequenceInputStream(certStream, privateKeyStream);
// Build a key store using the combined stream.
return SecurityUtils.createMtlsKeyStore(certAndPrivateKeyStream);
} catch (CertificateSourceUnavailableException e) {
// Throw the CertificateSourceUnavailableException without wrapping.
throw e;
} catch (Exception e) {
// Wrap all other exception types to an IOException.
throw new IOException(e);
} finally {
if (certStream != null) {
certStream.close();
}
if (privateKeyStream != null) {
privateKeyStream.close();
}
if (certAndPrivateKeyStream != null) {
certAndPrivateKeyStream.close();
}
}
}
private WorkloadCertificateConfiguration getWorkloadCertificateConfiguration()
throws IOException {
File certConfig;
if (this.certConfigPathOverride != null) {
certConfig = new File(certConfigPathOverride);
} else {
String envCredentialsPath = getEnv(CERTIFICATE_CONFIGURATION_ENV_VARIABLE);
if (!Strings.isNullOrEmpty(envCredentialsPath)) {
certConfig = new File(envCredentialsPath);
} else {
certConfig = getWellKnownCertificateConfigFile();
}
}
InputStream certConfigStream = null;
try {
if (!isFile(certConfig)) {
// Path will be put in the message from the catch block below
throw new CertificateSourceUnavailableException("File does not exist.");
}
certConfigStream = createInputStream(certConfig);
return WorkloadCertificateConfiguration.fromCertificateConfigurationStream(certConfigStream);
} finally {
if (certConfigStream != null) {
certConfigStream.close();
}
}
}
/*
* Start of methods to allow overriding in the test code to isolate from the environment.
*/
boolean isFile(File file) {
return file.isFile();
}
InputStream createInputStream(File file) throws FileNotFoundException {
return new FileInputStream(file);
}
String getEnv(String name) {
return System.getenv(name);
}
String getOsName() {
return getProperty("os.name", "").toLowerCase(Locale.US);
}
String getProperty(String property, String def) {
return System.getProperty(property, def);
}
/*
* End of methods to allow overriding in the test code to isolate from the environment.
*/
private File getWellKnownCertificateConfigFile() {
File cloudConfigPath;
String envPath = getEnv("CLOUDSDK_CONFIG");
if (envPath != null) {
cloudConfigPath = new File(envPath);
} else if (getOsName().indexOf("windows") >= 0) {
File appDataPath = new File(getEnv("APPDATA"));
cloudConfigPath = new File(appDataPath, CLOUDSDK_CONFIG_DIRECTORY);
} else {
File configPath = new File(getProperty("user.home", ""), ".config");
cloudConfigPath = new File(configPath, CLOUDSDK_CONFIG_DIRECTORY);
}
return new File(cloudConfigPath, WELL_KNOWN_CERTIFICATE_CONFIG_FILE);
}
}