// 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.authandtls;

import com.github.benmanes.caffeine.cache.Cache;
import com.google.auth.Credentials;
import com.google.auth.oauth2.GoogleCredentials;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.devtools.build.lib.authandtls.credentialhelper.CredentialHelperCredentials;
import com.google.devtools.build.lib.authandtls.credentialhelper.CredentialHelperEnvironment;
import com.google.devtools.build.lib.authandtls.credentialhelper.CredentialHelperProvider;
import com.google.devtools.build.lib.events.Event;
import com.google.devtools.build.lib.runtime.CommandLinePathFactory;
import com.google.devtools.build.lib.vfs.FileSystem;
import com.google.devtools.build.lib.vfs.Path;
import io.grpc.CallCredentials;
import io.grpc.ClientInterceptor;
import io.grpc.ManagedChannel;
import io.grpc.auth.MoreCallCredentials;
import io.grpc.netty.GrpcSslContexts;
import io.grpc.netty.NegotiationType;
import io.grpc.netty.NettyChannelBuilder;
import io.netty.channel.EventLoopGroup;
import io.netty.channel.epoll.Epoll;
import io.netty.channel.epoll.EpollDomainSocketChannel;
import io.netty.channel.epoll.EpollEventLoopGroup;
import io.netty.channel.kqueue.KQueue;
import io.netty.channel.kqueue.KQueueDomainSocketChannel;
import io.netty.channel.kqueue.KQueueEventLoopGroup;
import io.netty.channel.unix.DomainSocketAddress;
import io.netty.handler.ssl.SslContext;
import io.netty.handler.ssl.SslContextBuilder;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.net.URI;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import javax.annotation.Nullable;

/** Utility methods for using {@link AuthAndTLSOptions} with Google Cloud. */
public final class GoogleAuthUtils {

  /**
   * Create a new gRPC {@link ManagedChannel}.
   *
   * @throws IOException in case the channel can't be constructed.
   */
  public static ManagedChannel newChannel(
      @Nullable Executor executor,
      String target,
      String proxy,
      AuthAndTLSOptions options,
      @Nullable List<ClientInterceptor> interceptors)
      throws IOException {
    Preconditions.checkNotNull(target);
    Preconditions.checkNotNull(options);

    SslContext sslContext =
        isTlsEnabled(target)
            ? createSSlContext(
                options.tlsCertificate, options.tlsClientCertificate, options.tlsClientKey)
            : null;

    String targetUrl = convertTargetScheme(target);
    try {
      NettyChannelBuilder builder =
          newNettyChannelBuilder(targetUrl, proxy)
              .executor(executor)
              .negotiationType(
                  isTlsEnabled(target) ? NegotiationType.TLS : NegotiationType.PLAINTEXT);
      if (options.grpcKeepaliveTime != null) {
        builder.keepAliveTime(options.grpcKeepaliveTime.getSeconds(), TimeUnit.SECONDS);
        builder.keepAliveTimeout(options.grpcKeepaliveTimeout.getSeconds(), TimeUnit.SECONDS);
      }
      if (interceptors != null) {
        builder.intercept(interceptors);
      }
      if (sslContext != null) {
        builder.sslContext(sslContext);
        if (options.tlsAuthorityOverride != null) {
          builder.overrideAuthority(options.tlsAuthorityOverride);
        }
      }
      return builder.build();
    } catch (RuntimeException e) {
      // gRPC might throw all kinds of RuntimeExceptions: StatusRuntimeException,
      // IllegalStateException, NullPointerException, ...
      String message = "Failed to connect to '%s': %s";
      throw new IOException(String.format(message, targetUrl, e.getMessage()));
    }
  }

  /**
   * Converts 'grpc(s)' into an empty protocol, because 'grpc(s)' is not a widely supported scheme
   * and is interpreted as 'dns' under the hood.
   *
   * @return target URL with converted scheme
   */
  private static String convertTargetScheme(String target) {
    return target.replace("grpcs://", "").replace("grpc://", "");
  }

  private static boolean isTlsEnabled(String target) {
    // 'grpcs://' or empty prefix => TLS-enabled
    // when no schema prefix is provided in URL, bazel will treat it as a gRPC request with TLS
    // enabled
    return !target.startsWith("grpc://") && !target.startsWith("unix:");
  }

  private static SslContext createSSlContext(
      @Nullable String rootCert, @Nullable String clientCert, @Nullable String clientKey)
      throws IOException {
    SslContextBuilder sslContextBuilder;
    try {
      sslContextBuilder = GrpcSslContexts.forClient();
    } catch (Exception e) {
      String message = "Failed to init TLS infrastructure: " + e.getMessage();
      throw new IOException(message, e);
    }
    if (rootCert != null) {
      try {
        sslContextBuilder.trustManager(new File(rootCert));
      } catch (Exception e) {
        String message = "Failed to init TLS infrastructure using '%s' as root certificate: %s";
        message = String.format(message, rootCert, e.getMessage());
        throw new IOException(message, e);
      }
    }
    if (clientCert != null && clientKey != null) {
      try {
        sslContextBuilder.keyManager(new File(clientCert), new File(clientKey));
      } catch (Exception e) {
        String message = "Failed to init TLS infrastructure using '%s' as client certificate: %s";
        message = String.format(message, clientCert, e.getMessage());
        throw new IOException(message, e);
      }
    }
    try {
      return sslContextBuilder.build();
    } catch (Exception e) {
      String message = "Failed to init TLS infrastructure: " + e.getMessage();
      throw new IOException(message, e);
    }
  }

  private static EventLoopGroup currentEventLoopGroup = null;

  private static synchronized EventLoopGroup getEventLoopGroup() throws IOException {
    if (currentEventLoopGroup == null) {
      if (KQueue.isAvailable()) {
        currentEventLoopGroup = new KQueueEventLoopGroup();
      } else if (Epoll.isAvailable()) {
        currentEventLoopGroup = new EpollEventLoopGroup();
      } else {
        throw new IOException("Creating event loop groups is unsupported on this platform");
      }
    }
    return currentEventLoopGroup;
  }

  private static NettyChannelBuilder newUnixNettyChannelBuilder(String target) throws IOException {
    DomainSocketAddress address = new DomainSocketAddress(target.replaceFirst("^unix:", ""));
    NettyChannelBuilder builder =
        NettyChannelBuilder.forAddress(address).eventLoopGroup(getEventLoopGroup());
    if (KQueue.isAvailable()) {
      return builder.channelType(KQueueDomainSocketChannel.class);
    }
    if (Epoll.isAvailable()) {
      return builder.channelType(EpollDomainSocketChannel.class);
    }

    throw new IOException("Unix domain sockets are unsupported on this platform");
  }

  private static NettyChannelBuilder newNettyChannelBuilder(String targetUrl, String proxy)
      throws IOException {
    if (targetUrl.startsWith("unix:")) {
      return newUnixNettyChannelBuilder(targetUrl);
    }

    if (Strings.isNullOrEmpty(proxy)) {
      return NettyChannelBuilder.forTarget(targetUrl).defaultLoadBalancingPolicy("round_robin");
    }

    if (!proxy.startsWith("unix:")) {
      throw new IOException("Remote proxy unsupported: " + proxy);
    }

    return newUnixNettyChannelBuilder(proxy).overrideAuthority(targetUrl);
  }

  /**
   * Create a new {@link CallCredentials} object from the authentication flags, or null if no flags
   * are set.
   *
   * @throws IOException in case the credentials can't be constructed.
   */
  @Nullable
  public static CallCredentials newGoogleCallCredentials(AuthAndTLSOptions options)
      throws IOException {
    Optional<Credentials> creds = newGoogleCredentials(options);
    if (creds.isPresent()) {
      return MoreCallCredentials.from(creds.get());
    }
    return null;
  }

  /**
   * Create a new {@link CallCredentialsProvider} object from {@link Credentials} or return {@link
   * CallCredentialsProvider#NO_CREDENTIALS} if it is {@code null}.
   */
  public static CallCredentialsProvider newCallCredentialsProvider(@Nullable Credentials creds) {
    if (creds != null) {
      return new GoogleAuthCallCredentialsProvider(creds);
    }
    return CallCredentialsProvider.NO_CREDENTIALS;
  }

  /**
   * Create a new {@link Credentials} retrieving call credentials in the following order:
   *
   * <ol>
   *   <li>If a Credential Helper is configured for the scope, use the credentials provided by the
   *       helper.
   *   <li>If (Google) authentication is enabled by flags, use it to create credentials.
   *   <li>Use {@code .netrc} to provide credentials if exists.
   * </ol>
   *
   * @throws IOException in case the credentials can't be constructed.
   */
  public static Credentials newCredentials(
      CredentialHelperEnvironment credentialHelperEnvironment,
      Cache<URI, ImmutableMap<String, ImmutableList<String>>> credentialCache,
      CommandLinePathFactory commandLinePathFactory,
      FileSystem fileSystem,
      AuthAndTLSOptions authAndTlsOptions)
      throws IOException {
    Preconditions.checkNotNull(credentialHelperEnvironment);
    Preconditions.checkNotNull(commandLinePathFactory);
    Preconditions.checkNotNull(fileSystem);
    Preconditions.checkNotNull(authAndTlsOptions);

    Optional<Credentials> fallbackCredentials = newGoogleCredentials(authAndTlsOptions);

    if (fallbackCredentials.isEmpty()) {
      // Fallback to .netrc if it exists.
      try {
        fallbackCredentials =
            newCredentialsFromNetrc(credentialHelperEnvironment.getClientEnvironment(), fileSystem);
      } catch (IOException e) {
        // TODO(yannic): Make this fail the build.
        credentialHelperEnvironment.getEventReporter().handle(Event.warn(e.getMessage()));
      }
    }

    return new CredentialHelperCredentials(
        newCredentialHelperProvider(
            credentialHelperEnvironment,
            commandLinePathFactory,
            authAndTlsOptions.credentialHelpers),
        credentialHelperEnvironment,
        credentialCache,
        fallbackCredentials);
  }

  /**
   * Create a new {@link Credentials} object from the authentication flags, or null if no flags are
   * set.
   *
   * @throws IOException in case the credentials can't be constructed.
   */
  private static Optional<Credentials> newGoogleCredentials(AuthAndTLSOptions options)
      throws IOException {
    Preconditions.checkNotNull(options);
    if (options.googleCredentials != null) {
      // Credentials from file
      try (InputStream authFile = new FileInputStream(options.googleCredentials)) {
        return Optional.of(newGoogleCredentialsFromFile(authFile, options.googleAuthScopes));
      } catch (FileNotFoundException e) {
        String message =
            String.format(
                "Could not open auth credentials file '%s': %s",
                options.googleCredentials, e.getMessage());
        throw new IOException(message, e);
      }
    } else if (options.useGoogleDefaultCredentials) {
      return Optional.of(
          newGoogleCredentialsFromFile(
              null /* Google Application Default Credentials */, options.googleAuthScopes));
    }
    return Optional.empty();
  }

  /**
   * Create a new {@link Credentials} object from credential file and given authentication scopes.
   *
   * @throws IOException in case the credentials can't be constructed.
   */
  @VisibleForTesting
  public static Credentials newGoogleCredentialsFromFile(
      @Nullable InputStream credentialsFile, List<String> authScopes) throws IOException {
    try {
      GoogleCredentials creds =
          credentialsFile == null
              ? GoogleCredentials.getApplicationDefault()
              : GoogleCredentials.fromStream(credentialsFile);
      if (!authScopes.isEmpty()) {
        creds = creds.createScoped(authScopes);
      }
      return creds;
    } catch (Exception e) {
      String message = "Failed to init auth credentials: " + e.getMessage();
      throw new IOException(message, e);
    }
  }

  /**
   * Create a new {@link Credentials} object by parsing the .netrc file with following order to
   * search it:
   *
   * <ol>
   *   <li>If environment variable $NETRC exists, use it as the path to the .netrc file
   *   <li>Fallback to $HOME/.netrc
   * </ol>
   *
   * @return the {@link Credentials} object or {@code null} if there is no .netrc file.
   * @throws IOException in case the credentials can't be constructed.
   */
  @VisibleForTesting
  static Optional<Credentials> newCredentialsFromNetrc(
      Map<String, String> clientEnv, FileSystem fileSystem) throws IOException {
    Optional<String> netrcFileString =
        Optional.ofNullable(clientEnv.get("NETRC"))
            .or(() -> Optional.ofNullable(clientEnv.get("HOME")).map(home -> home + "/.netrc"));
    if (netrcFileString.isEmpty()) {
      return Optional.empty();
    }

    Path netrcFile = fileSystem.getPath(netrcFileString.get());
    if (!netrcFile.exists()) {
      return Optional.empty();
    }

    try {
      Netrc netrc = NetrcParser.parseAndClose(netrcFile.getInputStream());
      return Optional.of(new NetrcCredentials(netrc));
    } catch (IOException e) {
      throw new IOException(
          "Failed to parse " + netrcFile.getPathString() + ": " + e.getMessage(), e);
    }
  }

  public static CredentialHelperProvider newCredentialHelperProvider(
      CredentialHelperEnvironment environment,
      CommandLinePathFactory pathFactory,
      List<AuthAndTLSOptions.CredentialHelperOption> helpers)
      throws IOException {
    Preconditions.checkNotNull(environment);
    Preconditions.checkNotNull(pathFactory);
    Preconditions.checkNotNull(helpers);

    CredentialHelperProvider.Builder builder = CredentialHelperProvider.builder();
    for (AuthAndTLSOptions.CredentialHelperOption helper : helpers) {
      Optional<String> scope = helper.getScope();
      Path path = pathFactory.create(environment.getClientEnvironment(), helper.getPath());
      if (scope.isPresent()) {
        builder.add(scope.get(), path);
      } else {
        builder.add(path);
      }
    }
    return builder.build();
  }
}
