|
19 | 19 | import build.bazel.remote.execution.v2.DigestFunction;
|
20 | 20 | import build.bazel.remote.execution.v2.ServerCapabilities;
|
21 | 21 | import com.google.auth.Credentials;
|
| 22 | +import com.google.auto.value.AutoValue; |
22 | 23 | import com.google.common.annotations.VisibleForTesting;
|
23 | 24 | import com.google.common.base.Ascii;
|
24 | 25 | import com.google.common.base.Preconditions;
|
|
50 | 51 | import com.google.devtools.build.lib.authandtls.Netrc;
|
51 | 52 | import com.google.devtools.build.lib.authandtls.NetrcCredentials;
|
52 | 53 | import com.google.devtools.build.lib.authandtls.NetrcParser;
|
| 54 | +import com.google.devtools.build.lib.authandtls.credentialhelper.CredentialHelperCredentials; |
| 55 | +import com.google.devtools.build.lib.authandtls.credentialhelper.CredentialHelperEnvironment; |
| 56 | +import com.google.devtools.build.lib.authandtls.credentialhelper.CredentialHelperProvider; |
53 | 57 | import com.google.devtools.build.lib.bazel.repository.downloader.Downloader;
|
54 | 58 | import com.google.devtools.build.lib.buildeventstream.BuildEventArtifactUploader;
|
55 | 59 | import com.google.devtools.build.lib.buildeventstream.LocalFilesArtifactUploader;
|
|
78 | 82 | import com.google.devtools.build.lib.runtime.BuildEventArtifactUploaderFactory;
|
79 | 83 | import com.google.devtools.build.lib.runtime.Command;
|
80 | 84 | import com.google.devtools.build.lib.runtime.CommandEnvironment;
|
| 85 | +import com.google.devtools.build.lib.runtime.CommandLinePathFactory; |
81 | 86 | import com.google.devtools.build.lib.runtime.RepositoryRemoteExecutor;
|
82 | 87 | import com.google.devtools.build.lib.runtime.RepositoryRemoteExecutorFactory;
|
83 | 88 | import com.google.devtools.build.lib.runtime.ServerBuilder;
|
|
103 | 108 | import io.reactivex.rxjava3.plugins.RxJavaPlugins;
|
104 | 109 | import java.io.IOException;
|
105 | 110 | import java.net.URI;
|
106 |
| -import java.net.URISyntaxException; |
107 | 111 | import java.util.HashSet;
|
108 | 112 | import java.util.List;
|
109 | 113 | import java.util.Map;
|
@@ -217,12 +221,12 @@ private void initHttpAndDiskCache(
|
217 | 221 | try {
|
218 | 222 | creds =
|
219 | 223 | newCredentials(
|
220 |
| - env.getClientEnv(), |
| 224 | + env.getCommandLinePathFactory(), |
| 225 | + newCredentialHelperEnvironment(env, authAndTlsOptions), |
221 | 226 | env.getRuntime().getFileSystem(),
|
222 |
| - env.getReporter(), |
223 | 227 | authAndTlsOptions,
|
224 | 228 | remoteOptions);
|
225 |
| - } catch (IOException e) { |
| 229 | + } catch (IOException | IllegalArgumentException e) { |
226 | 230 | handleInitFailure(env, e, Code.CREDENTIALS_INIT_FAILURE);
|
227 | 231 | return;
|
228 | 232 | }
|
@@ -432,12 +436,12 @@ public void beforeCommand(CommandEnvironment env) throws AbruptExitException {
|
432 | 436 | callCredentialsProvider =
|
433 | 437 | GoogleAuthUtils.newCallCredentialsProvider(
|
434 | 438 | newCredentials(
|
435 |
| - env.getClientEnv(), |
| 439 | + env.getCommandLinePathFactory(), |
| 440 | + newCredentialHelperEnvironment(env, authAndTlsOptions), |
436 | 441 | env.getRuntime().getFileSystem(),
|
437 |
| - env.getReporter(), |
438 | 442 | authAndTlsOptions,
|
439 | 443 | remoteOptions));
|
440 |
| - } catch (IOException e) { |
| 444 | + } catch (IOException | IllegalArgumentException e) { |
441 | 445 | handleInitFailure(env, e, Code.CREDENTIALS_INIT_FAILURE);
|
442 | 446 | return;
|
443 | 447 | }
|
@@ -645,7 +649,7 @@ public void beforeCommand(CommandEnvironment env) throws AbruptExitException {
|
645 | 649 | }
|
646 | 650 |
|
647 | 651 | private static void handleInitFailure(
|
648 |
| - CommandEnvironment env, IOException e, Code remoteExecutionCode) { |
| 652 | + CommandEnvironment env, Exception e, Code remoteExecutionCode) { |
649 | 653 | env.getReporter().handle(Event.error(e.getMessage()));
|
650 | 654 | env.getBlazeModuleEnvironment()
|
651 | 655 | .exit(
|
@@ -1096,38 +1100,108 @@ static Credentials newCredentialsFromNetrc(Map<String, String> clientEnv, FileSy
|
1096 | 1100 | */
|
1097 | 1101 | @VisibleForTesting
|
1098 | 1102 | static Credentials newCredentials(
|
1099 |
| - Map<String, String> clientEnv, |
| 1103 | + CommandLinePathFactory commandLinePathFactory, |
| 1104 | + CredentialHelperEnvironment credentialHelperEnvironment, |
1100 | 1105 | FileSystem fileSystem,
|
1101 |
| - Reporter reporter, |
1102 | 1106 | AuthAndTLSOptions authAndTlsOptions,
|
1103 | 1107 | RemoteOptions remoteOptions)
|
1104 | 1108 | throws IOException {
|
1105 |
| - Credentials creds = GoogleAuthUtils.newCredentials(authAndTlsOptions); |
| 1109 | + // TODO(yannic): Change `GoogleAuthUtils.newCredentials` to return `Optional`. |
| 1110 | + Optional<Credentials> creds = Optional.ofNullable(GoogleAuthUtils.newCredentials(authAndTlsOptions)); |
| 1111 | + creds = creds.or(() -> { |
| 1112 | + // Fallback to .netrc if it exists. |
1106 | 1113 |
|
1107 |
| - // Fallback to .netrc if it exists |
1108 |
| - if (creds == null) { |
1109 | 1114 | try {
|
1110 |
| - creds = newCredentialsFromNetrc(clientEnv, fileSystem); |
| 1115 | + // TODO(yannic): Change `newCredentialsFromNetrc` to return `Optional`. |
| 1116 | + return Optional.ofNullable( |
| 1117 | + newCredentialsFromNetrc( |
| 1118 | + credentialHelperEnvironment.getClientEnvironment(), fileSystem)); |
1111 | 1119 | } catch (IOException e) {
|
1112 |
| - reporter.handle(Event.warn(e.getMessage())); |
| 1120 | + credentialHelperEnvironment.getEventReporter().handle(Event.warn(e.getMessage())); |
| 1121 | + return Optional.empty(); |
1113 | 1122 | }
|
1114 |
| - |
1115 |
| - try { |
1116 |
| - if (creds != null |
1117 |
| - && remoteOptions.remoteCache != null |
1118 |
| - && Ascii.toLowerCase(remoteOptions.remoteCache).startsWith("http://") |
1119 |
| - && !creds.getRequestMetadata(new URI(remoteOptions.remoteCache)).isEmpty()) { |
1120 |
| - reporter.handle( |
1121 |
| - Event.warn( |
1122 |
| - "Username and password from .netrc is transmitted in plaintext to " |
1123 |
| - + remoteOptions.remoteCache |
1124 |
| - + ". Please consider using an HTTPS endpoint.")); |
1125 |
| - } |
1126 |
| - } catch (URISyntaxException e) { |
1127 |
| - throw new IOException(e.getMessage(), e); |
| 1123 | + }); |
| 1124 | + |
| 1125 | + if (creds.isPresent()) { |
| 1126 | + if (remoteOptions.remoteCache != null |
| 1127 | + && Ascii.toLowerCase(remoteOptions.remoteCache).startsWith("http://") |
| 1128 | + && !creds.get().getRequestMetadata(URI.create(remoteOptions.remoteCache)).isEmpty()) { |
| 1129 | + credentialHelperEnvironment.getEventReporter().handle( |
| 1130 | + Event.warn( |
| 1131 | + "Username and password from .netrc is transmitted in plaintext to " |
| 1132 | + + remoteOptions.remoteCache |
| 1133 | + + ". Please consider using an HTTPS endpoint.")); |
1128 | 1134 | }
|
1129 | 1135 | }
|
1130 | 1136 |
|
1131 |
| - return creds; |
| 1137 | + CredentialHelperProvider credentialHelperProvider = |
| 1138 | + newCredentialHelperProvider( |
| 1139 | + credentialHelperEnvironment, |
| 1140 | + commandLinePathFactory, |
| 1141 | + authAndTlsOptions.credentialHelpers); |
| 1142 | + return new CredentialHelperCredentials( |
| 1143 | + credentialHelperProvider, credentialHelperEnvironment, creds); |
| 1144 | + } |
| 1145 | + |
| 1146 | + private CredentialHelperEnvironment newCredentialHelperEnvironment( |
| 1147 | + CommandEnvironment env, AuthAndTLSOptions authAndTlsOptions) { |
| 1148 | + Preconditions.checkNotNull(env); |
| 1149 | + Preconditions.checkNotNull(authAndTlsOptions); |
| 1150 | + |
| 1151 | + return CredentialHelperEnvironment.newBuilder() |
| 1152 | + .setEventReporter(env.getReporter()) |
| 1153 | + .setWorkspacePath(env.getWorkspace()) |
| 1154 | + .setClientEnvironment(env.getClientEnv()) |
| 1155 | + .setHelperExecutionTimeout(authAndTlsOptions.credentialHelperTimeout) |
| 1156 | + .build(); |
| 1157 | + } |
| 1158 | + |
| 1159 | + @VisibleForTesting |
| 1160 | + static CredentialHelperProvider newCredentialHelperProvider( |
| 1161 | + CredentialHelperEnvironment environment, |
| 1162 | + CommandLinePathFactory pathFactory, |
| 1163 | + List<String> inputs) |
| 1164 | + throws IOException { |
| 1165 | + Preconditions.checkNotNull(environment); |
| 1166 | + Preconditions.checkNotNull(pathFactory); |
| 1167 | + Preconditions.checkNotNull(inputs); |
| 1168 | + |
| 1169 | + CredentialHelperProvider.Builder builder = CredentialHelperProvider.builder(); |
| 1170 | + for (String input : inputs) { |
| 1171 | + ScopedCredentialHelper helper = parseCredentialHelperFlag(environment, pathFactory, input); |
| 1172 | + builder.add(helper.getScope(), helper.getPath()); |
| 1173 | + } |
| 1174 | + return builder.build(); |
| 1175 | + } |
| 1176 | + |
| 1177 | + @VisibleForTesting |
| 1178 | + static ScopedCredentialHelper parseCredentialHelperFlag( |
| 1179 | + CredentialHelperEnvironment environment, CommandLinePathFactory pathFactory, String input) |
| 1180 | + throws IOException { |
| 1181 | + Preconditions.checkNotNull(environment); |
| 1182 | + Preconditions.checkNotNull(pathFactory); |
| 1183 | + Preconditions.checkNotNull(input); |
| 1184 | + |
| 1185 | + int pos = input.indexOf('='); |
| 1186 | + if (pos > 0) { |
| 1187 | + String scope = input.substring(0, pos); |
| 1188 | + String path = input.substring(pos + 1); |
| 1189 | + return new AutoValue_RemoteModule_ScopedCredentialHelper( |
| 1190 | + Optional.of(scope), pathFactory.create(environment.getClientEnvironment(), path)); |
| 1191 | + } |
| 1192 | + |
| 1193 | + // `input` does not specify a scope. |
| 1194 | + return new AutoValue_RemoteModule_ScopedCredentialHelper( |
| 1195 | + Optional.empty(), pathFactory.create(environment.getClientEnvironment(), input)); |
| 1196 | + } |
| 1197 | + |
| 1198 | + @VisibleForTesting |
| 1199 | + @AutoValue |
| 1200 | + static abstract class ScopedCredentialHelper { |
| 1201 | + /** Returns the scope of the credential helper (if any). */ |
| 1202 | + public abstract Optional<String> getScope(); |
| 1203 | + |
| 1204 | + /** Returns the path of the credential helper. */ |
| 1205 | + public abstract Path getPath(); |
1132 | 1206 | }
|
1133 | 1207 | }
|
0 commit comments