aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/main/java/com/google/devtools/build/lib/remote/ChannelOptions.java
blob: 9a3f736455df2566a48987d4ceac8e3265ebef3c (plain)
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
// Copyright 2017 The Bazel Authors. All rights reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package com.google.devtools.build.lib.remote;

import com.google.auth.oauth2.GoogleCredentials;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.devtools.build.lib.authandtls.AuthAndTLSOptions;
import com.google.devtools.build.lib.concurrent.ThreadSafety.ThreadSafe;
import io.grpc.CallCredentials;
import io.grpc.auth.MoreCallCredentials;
import io.grpc.netty.GrpcSslContexts;
import io.netty.handler.ssl.SslContext;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import javax.annotation.Nullable;

/** Instantiate all authentication helpers from build options. */
@ThreadSafe
public final class ChannelOptions {
  private final boolean tlsEnabled;
  private final SslContext sslContext;
  private final String tlsAuthorityOverride;
  private final CallCredentials credentials;

  private ChannelOptions(
      boolean tlsEnabled,
      SslContext sslContext,
      String tlsAuthorityOverride,
      CallCredentials credentials) {
    this.tlsEnabled = tlsEnabled;
    this.sslContext = sslContext;
    this.tlsAuthorityOverride = tlsAuthorityOverride;
    this.credentials = credentials;
  }

  public boolean tlsEnabled() {
    return tlsEnabled;
  }

  public CallCredentials getCallCredentials() {
    return credentials;
  }

  public String getTlsAuthorityOverride() {
    return tlsAuthorityOverride;
  }

  public SslContext getSslContext() {
    return sslContext;
  }

  public static ChannelOptions create(AuthAndTLSOptions options) throws IOException {
    if (options.authCredentials != null) {
      try (InputStream authFile = new FileInputStream(options.authCredentials)) {
        return create(options, authFile);
      } catch (FileNotFoundException e) {
        String message = String.format("Could not open auth credentials file '%s': %s",
            options.authCredentials, e.getMessage());
        throw new IOException(message, e);
      }
    } else {
      return create(options, null);
    }
  }

  @VisibleForTesting
  static ChannelOptions create(
      AuthAndTLSOptions options,
      @Nullable InputStream credentialsFile) throws IOException {
    final SslContext sslContext =
        options.tlsEnabled ? createSSlContext(options.tlsCertificate) : null;

    final CallCredentials callCredentials =
        options.authEnabled ? createCallCredentials(credentialsFile, options.authScope) : null;

    return new ChannelOptions(
        sslContext != null, sslContext, options.tlsAuthorityOverride, callCredentials);
  }

  private static CallCredentials createCallCredentials(@Nullable InputStream credentialsFile,
      @Nullable String authScope) throws IOException {
    try {
      GoogleCredentials creds =
          credentialsFile == null
              ? GoogleCredentials.getApplicationDefault()
              : GoogleCredentials.fromStream(credentialsFile);
      if (authScope != null) {
        creds = creds.createScoped(ImmutableList.of(authScope));
      }
      return MoreCallCredentials.from(creds);
    } catch (IOException e) {
      String message = "Failed to init auth credentials for remote caching/execution: "
          + e.getMessage();
      throw new IOException(message, e);
    }
  }

  private static SslContext createSSlContext(@Nullable String rootCert) throws IOException {
    if (rootCert == null) {
      try {
        return GrpcSslContexts.forClient().build();
      } catch (Exception e) {
        String message = "Failed to init TLS infrastructure for remote caching/execution: "
            + e.getMessage();
        throw new IOException(message, e);
      }
    } else {
      try {
        return GrpcSslContexts.forClient().trustManager(new File(rootCert)).build();
      } catch (Exception e) {
        String message = "Failed to init TLS infrastructure for remote caching/execution using "
            + "'%s' as root certificate: %s";
        message = String.format(message, rootCert, e.getMessage());
        throw new IOException(message, e);
      }
    }
  }
}