Skip to content

Commit e7e8562

Browse files
committed
Add netrc support to --bes_backend
Progress on bazelbuild#15856 Fixes bazelbuild#15928
1 parent b6f580a commit e7e8562

File tree

12 files changed

+235
-192
lines changed

12 files changed

+235
-192
lines changed

src/main/java/com/google/devtools/build/lib/authandtls/BUILD

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ java_library(
1515
srcs = glob(["*.java"]),
1616
deps = [
1717
"//src/main/java/com/google/devtools/build/lib/concurrent",
18+
"//src/main/java/com/google/devtools/build/lib/events",
19+
"//src/main/java/com/google/devtools/build/lib/vfs",
1820
"//src/main/java/com/google/devtools/common/options",
1921
"//third_party:auth",
2022
"//third_party:auto_value",

src/main/java/com/google/devtools/build/lib/authandtls/GoogleAuthUtils.java

Lines changed: 97 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
import com.google.common.annotations.VisibleForTesting;
2020
import com.google.common.base.Preconditions;
2121
import com.google.common.base.Strings;
22+
import com.google.devtools.build.lib.vfs.FileSystem;
23+
import com.google.devtools.build.lib.vfs.Path;
2224
import io.grpc.CallCredentials;
2325
import io.grpc.ClientInterceptor;
2426
import io.grpc.ManagedChannel;
@@ -41,6 +43,8 @@
4143
import java.io.IOException;
4244
import java.io.InputStream;
4345
import java.util.List;
46+
import java.util.Map;
47+
import java.util.Optional;
4448
import java.util.concurrent.Executor;
4549
import java.util.concurrent.TimeUnit;
4650
import javax.annotation.Nullable;
@@ -191,7 +195,20 @@ private static NettyChannelBuilder newNettyChannelBuilder(String targetUrl, Stri
191195
* @throws IOException in case the call credentials can't be constructed.
192196
*/
193197
@Nullable
194-
public static CallCredentials newCallCredentials(AuthAndTLSOptions options) throws IOException {
198+
public static CallCredentials newCallCredentials(
199+
Map<String, String> clientEnv,
200+
FileSystem fileSystem,
201+
AuthAndTLSOptions options) throws IOException {
202+
Credentials creds = newCredentials(clientEnv, fileSystem, options);
203+
if (creds != null) {
204+
return MoreCallCredentials.from(creds);
205+
}
206+
return null;
207+
}
208+
209+
@Nullable
210+
@VisibleForTesting
211+
public static CallCredentials newCallCredentialsForTesting(AuthAndTLSOptions options) throws IOException {
195212
Credentials creds = newCredentials(options);
196213
if (creds != null) {
197214
return MoreCallCredentials.from(creds);
@@ -217,12 +234,46 @@ public static CallCredentialsProvider newCallCredentialsProvider(@Nullable Crede
217234
*/
218235
@Nullable
219236
public static Credentials newCredentials(@Nullable AuthAndTLSOptions options) throws IOException {
237+
Optional<Credentials> credentials = newGoogleCredentials(options);
238+
239+
return credentials.orElse(null);
240+
}
241+
242+
/**
243+
* Create a new {@link Credentials} with following order:
244+
*
245+
* <ol>
246+
* <li>If authentication enabled by flags, use it to create credentials
247+
* <li>Use .netrc to provide credentials if exists
248+
* <li>Otherwise, return {@code null}
249+
* </ol>
250+
*
251+
* @throws IOException in case the credentials can't be constructed.
252+
*/
253+
@VisibleForTesting
254+
public static Credentials newCredentials(
255+
Map<String, String> clientEnv,
256+
FileSystem fileSystem,
257+
AuthAndTLSOptions authAndTlsOptions)
258+
throws IOException {
259+
Optional<Credentials> credentials = newGoogleCredentials(authAndTlsOptions);
260+
261+
if (credentials.isEmpty()) {
262+
// Fallback to .netrc if it exists.
263+
credentials = newCredentialsFromNetrc(clientEnv, fileSystem);
264+
}
265+
266+
return credentials.orElse(null);
267+
}
268+
269+
private static Optional<Credentials> newGoogleCredentials(
270+
@Nullable AuthAndTLSOptions options) throws IOException {
220271
if (options == null) {
221-
return null;
272+
return Optional.empty();
222273
} else if (options.googleCredentials != null) {
223274
// Credentials from file
224275
try (InputStream authFile = new FileInputStream(options.googleCredentials)) {
225-
return newCredentials(authFile, options.googleAuthScopes);
276+
return Optional.of(newGoogleCredentials(authFile, options.googleAuthScopes));
226277
} catch (FileNotFoundException e) {
227278
String message =
228279
String.format(
@@ -231,10 +282,10 @@ public static Credentials newCredentials(@Nullable AuthAndTLSOptions options) th
231282
throw new IOException(message, e);
232283
}
233284
} else if (options.useGoogleDefaultCredentials) {
234-
return newCredentials(
235-
null /* Google Application Default Credentials */, options.googleAuthScopes);
285+
return Optional.of(newGoogleCredentials(
286+
null /* Google Application Default Credentials */, options.googleAuthScopes));
236287
}
237-
return null;
288+
return Optional.empty();
238289
}
239290

240291
/**
@@ -243,7 +294,7 @@ public static Credentials newCredentials(@Nullable AuthAndTLSOptions options) th
243294
* @throws IOException in case the credentials can't be constructed.
244295
*/
245296
@VisibleForTesting
246-
public static Credentials newCredentials(
297+
public static Credentials newGoogleCredentials(
247298
@Nullable InputStream credentialsFile, List<String> authScopes) throws IOException {
248299
try {
249300
GoogleCredentials creds =
@@ -259,4 +310,43 @@ public static Credentials newCredentials(
259310
throw new IOException(message, e);
260311
}
261312
}
313+
314+
/**
315+
* Create a new {@link Credentials} object by parsing the .netrc file with following order to
316+
* search it:
317+
*
318+
* <ol>
319+
* <li>If environment variable $NETRC exists, use it as the path to the .netrc file
320+
* <li>Fallback to $HOME/.netrc
321+
* </ol>
322+
*
323+
* @return the {@link Credentials} object or {@code null} if there is no .netrc file.
324+
* @throws IOException in case the credentials can't be constructed.
325+
*/
326+
@VisibleForTesting
327+
static Optional<Credentials> newCredentialsFromNetrc(Map<String, String> clientEnv, FileSystem fileSystem)
328+
throws IOException {
329+
Optional<String> netrcFileString =
330+
Optional.ofNullable(clientEnv.get("NETRC"))
331+
.or(
332+
() ->
333+
Optional.ofNullable(clientEnv.get("HOME"))
334+
.map(home -> home + "/.netrc"));
335+
if (netrcFileString.isEmpty()) {
336+
return Optional.empty();
337+
}
338+
339+
Path netrcFile = fileSystem.getPath(netrcFileString.get());
340+
if (!netrcFile.exists()) {
341+
return Optional.empty();
342+
}
343+
344+
try {
345+
Netrc netrc = NetrcParser.parseAndClose(netrcFile.getInputStream());
346+
return Optional.of(new NetrcCredentials(netrc));
347+
} catch (IOException e) {
348+
throw new IOException(
349+
"Failed to parse " + netrcFile.getPathString() + ": " + e.getMessage(), e);
350+
}
351+
}
262352
}

src/main/java/com/google/devtools/build/lib/buildeventservice/BazelBuildEventServiceModule.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
2424
import com.google.devtools.build.lib.authandtls.GoogleAuthUtils;
2525
import com.google.devtools.build.lib.buildeventservice.client.BuildEventServiceClient;
2626
import com.google.devtools.build.lib.buildeventservice.client.BuildEventServiceGrpcClient;
27+
import com.google.devtools.build.lib.runtime.CommandEnvironment;
2728
import io.grpc.ClientInterceptor;
2829
import io.grpc.ManagedChannel;
2930
import io.grpc.Metadata;
@@ -70,15 +71,16 @@ protected Class<BuildEventServiceOptions> optionsClass() {
7071

7172
@Override
7273
protected BuildEventServiceClient getBesClient(
73-
BuildEventServiceOptions besOptions, AuthAndTLSOptions authAndTLSOptions) throws IOException {
74+
CommandEnvironment env, BuildEventServiceOptions besOptions, AuthAndTLSOptions authAndTLSOptions) throws IOException {
7475
BackendConfig newConfig = BackendConfig.create(besOptions, authAndTLSOptions);
7576
if (client == null || !Objects.equals(config, newConfig)) {
7677
clearBesClient();
7778
config = newConfig;
7879
client =
7980
new BuildEventServiceGrpcClient(
8081
newGrpcChannel(config),
81-
GoogleAuthUtils.newCallCredentials(config.authAndTLSOptions()),
82+
GoogleAuthUtils.newCallCredentials(
83+
env.getClientEnv(), env.getRuntime().getFileSystem(), config.authAndTLSOptions()),
8284
makeGrpcInterceptor(config));
8385
}
8486
return client;

src/main/java/com/google/devtools/build/lib/buildeventservice/BuildEventServiceModule.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,7 @@ private BuildEventServiceTransport createBesTransport(
699699

700700
final BuildEventServiceClient besClient;
701701
try {
702-
besClient = getBesClient(besOptions, authTlsOptions);
702+
besClient = getBesClient(cmdEnv, besOptions, authTlsOptions);
703703
} catch (IOException | OptionsParsingException e) {
704704
reportError(
705705
reporter,
@@ -845,7 +845,7 @@ private static AbruptExitException createAbruptExitException(
845845
protected abstract Class<OptionsT> optionsClass();
846846

847847
protected abstract BuildEventServiceClient getBesClient(
848-
OptionsT besOptions, AuthAndTLSOptions authAndTLSOptions)
848+
CommandEnvironment env, OptionsT besOptions, AuthAndTLSOptions authAndTLSOptions)
849849
throws IOException, OptionsParsingException;
850850

851851
protected abstract void clearBesClient();

src/main/java/com/google/devtools/build/lib/remote/RemoteModule.java

Lines changed: 27 additions & 92 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@
4949
import com.google.devtools.build.lib.authandtls.AuthAndTLSOptions.UnresolvedScopedCredentialHelper;
5050
import com.google.devtools.build.lib.authandtls.CallCredentialsProvider;
5151
import com.google.devtools.build.lib.authandtls.GoogleAuthUtils;
52-
import com.google.devtools.build.lib.authandtls.Netrc;
53-
import com.google.devtools.build.lib.authandtls.NetrcCredentials;
54-
import com.google.devtools.build.lib.authandtls.NetrcParser;
5552
import com.google.devtools.build.lib.authandtls.credentialhelper.CredentialHelperEnvironment;
5653
import com.google.devtools.build.lib.authandtls.credentialhelper.CredentialHelperProvider;
5754
import com.google.devtools.build.lib.bazel.repository.downloader.Downloader;
@@ -1047,95 +1044,6 @@ RemoteActionContextProvider getActionContextProvider() {
10471044
return actionContextProvider;
10481045
}
10491046

1050-
/**
1051-
* Create a new {@link Credentials} object by parsing the .netrc file with following order to
1052-
* search it:
1053-
*
1054-
* <ol>
1055-
* <li>If environment variable $NETRC exists, use it as the path to the .netrc file
1056-
* <li>Fallback to $HOME/.netrc
1057-
* </ol>
1058-
*
1059-
* @return the {@link Credentials} object or {@code null} if there is no .netrc file.
1060-
* @throws IOException in case the credentials can't be constructed.
1061-
*/
1062-
@Nullable
1063-
@VisibleForTesting
1064-
static Credentials newCredentialsFromNetrc(Map<String, String> clientEnv, FileSystem fileSystem)
1065-
throws IOException {
1066-
String netrcFileString =
1067-
Optional.ofNullable(clientEnv.get("NETRC"))
1068-
.orElseGet(
1069-
() ->
1070-
Optional.ofNullable(clientEnv.get("HOME"))
1071-
.map(home -> home + "/.netrc")
1072-
.orElse(null));
1073-
if (netrcFileString == null) {
1074-
return null;
1075-
}
1076-
1077-
Path netrcFile = fileSystem.getPath(netrcFileString);
1078-
if (netrcFile.exists()) {
1079-
try {
1080-
Netrc netrc = NetrcParser.parseAndClose(netrcFile.getInputStream());
1081-
return new NetrcCredentials(netrc);
1082-
} catch (IOException e) {
1083-
throw new IOException(
1084-
"Failed to parse " + netrcFile.getPathString() + ": " + e.getMessage(), e);
1085-
}
1086-
} else {
1087-
return null;
1088-
}
1089-
}
1090-
1091-
/**
1092-
* Create a new {@link Credentials} with following order:
1093-
*
1094-
* <ol>
1095-
* <li>If authentication enabled by flags, use it to create credentials
1096-
* <li>Use .netrc to provide credentials if exists
1097-
* <li>Otherwise, return {@code null}
1098-
* </ol>
1099-
*
1100-
* @throws IOException in case the credentials can't be constructed.
1101-
*/
1102-
@VisibleForTesting
1103-
static Credentials newCredentials(
1104-
Map<String, String> clientEnv,
1105-
FileSystem fileSystem,
1106-
Reporter reporter,
1107-
AuthAndTLSOptions authAndTlsOptions,
1108-
RemoteOptions remoteOptions)
1109-
throws IOException {
1110-
Credentials creds = GoogleAuthUtils.newCredentials(authAndTlsOptions);
1111-
1112-
// Fallback to .netrc if it exists
1113-
if (creds == null) {
1114-
try {
1115-
creds = newCredentialsFromNetrc(clientEnv, fileSystem);
1116-
} catch (IOException e) {
1117-
reporter.handle(Event.warn(e.getMessage()));
1118-
}
1119-
1120-
try {
1121-
if (creds != null
1122-
&& remoteOptions.remoteCache != null
1123-
&& Ascii.toLowerCase(remoteOptions.remoteCache).startsWith("http://")
1124-
&& !creds.getRequestMetadata(new URI(remoteOptions.remoteCache)).isEmpty()) {
1125-
reporter.handle(
1126-
Event.warn(
1127-
"Username and password from .netrc is transmitted in plaintext to "
1128-
+ remoteOptions.remoteCache
1129-
+ ". Please consider using an HTTPS endpoint."));
1130-
}
1131-
} catch (URISyntaxException e) {
1132-
throw new IOException(e.getMessage(), e);
1133-
}
1134-
}
1135-
1136-
return creds;
1137-
}
1138-
11391047
@VisibleForTesting
11401048
static CredentialHelperProvider newCredentialHelperProvider(
11411049
CredentialHelperEnvironment environment,
@@ -1159,6 +1067,33 @@ static CredentialHelperProvider newCredentialHelperProvider(
11591067
return builder.build();
11601068
}
11611069

1070+
static Credentials newCredentials(
1071+
Map<String, String> clientEnv,
1072+
FileSystem fileSystem,
1073+
Reporter reporter,
1074+
AuthAndTLSOptions authAndTlsOptions,
1075+
RemoteOptions remoteOptions) throws IOException {
1076+
Credentials credentials = GoogleAuthUtils.newCredentials(clientEnv, fileSystem, authAndTlsOptions);
1077+
1078+
try {
1079+
if (credentials != null
1080+
&& remoteOptions.remoteCache != null
1081+
&& Ascii.toLowerCase(remoteOptions.remoteCache).startsWith("http://")
1082+
&& !credentials.getRequestMetadata(new URI(remoteOptions.remoteCache)).isEmpty()) {
1083+
// TODO(yannic): Make this a error aborting the build.
1084+
reporter.handle(
1085+
Event.warn(
1086+
"Credentials are transmitted in plaintext to "
1087+
+ remoteOptions.remoteCache
1088+
+ ". Please consider using an HTTPS endpoint."));
1089+
}
1090+
} catch (URISyntaxException e) {
1091+
throw new IOException(e.getMessage(), e);
1092+
}
1093+
1094+
return credentials;
1095+
}
1096+
11621097
@VisibleForTesting
11631098
@AutoValue
11641099
abstract static class ScopedCredentialHelper {

src/test/java/com/google/devtools/build/lib/authandtls/BUILD

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,11 @@ java_library(
2525
),
2626
deps = [
2727
"//src/main/java/com/google/devtools/build/lib/authandtls",
28+
"//src/main/java/com/google/devtools/build/lib/vfs",
29+
"//src/main/java/com/google/devtools/build/lib/vfs/inmemoryfs",
2830
"//src/main/java/com/google/devtools/common/options",
31+
"//src/test/java/com/google/devtools/build/lib/testutil",
32+
"//third_party:auth_checked_in",
2933
"//third_party:guava",
3034
"//third_party:junit4",
3135
"//third_party:truth",

0 commit comments

Comments
 (0)