All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.scalar.dl.client.config.ClientConfig Maven / Gradle / Ivy

There is a newer version: 3.10.0
Show newest version
/*
 * This file is part of the Scalar DL client SDK.
 * Copyright (c) 2019 Scalar, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU Affero General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU Affero General Public License for more details.
 *
 * You should have received a copy of the GNU Affero General Public License
 * along with this program.  If not, see .
 *
 * You can be released from the requirements of the license by purchasing
 * a commercial license. For more information, please contact Scalar, Inc.
 */
package com.scalar.dl.client.config;

import static com.google.common.base.Preconditions.checkArgument;

import com.google.common.base.Splitter;
import com.scalar.dl.ledger.config.TargetConfig;
import com.scalar.dl.ledger.util.PropertiesUtil;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import javax.annotation.Nonnull;
import javax.annotation.Nullable;
import javax.annotation.concurrent.Immutable;

@Immutable
@SuppressFBWarnings("JCIP_FIELD_ISNT_FINAL_IN_IMMUTABLE_CLASS")
public class ClientConfig {
  private static final String PREFIX = "scalar.dl.client.";
  /**
   * Optional. A hostname or an IP address of the server ("localhost" by default). It assumes that
   * there is a single endpoint that is given by DNS or a load balancer.
   */
  public static final String SERVER_HOST = PREFIX + "server.host";
  /** Optional. A port number of the server (50051 by default). */
  public static final String SERVER_PORT = PREFIX + "server.port";
  /** Optional. A port number of the server for privileged services (50052 by default). */
  public static final String SERVER_PRIVILEGED_PORT = PREFIX + "server.privileged_port";
  /**
   * Required. The holder ID of a certificate. It must be configured for each private key and unique
   * in the system.
   */
  public static final String CERT_HOLDER_ID = PREFIX + "cert_holder_id";
  /**
   * Optional. The version of the certificate (1 by default). Use another bigger integer if you need
   * to change your private key.
   */
  public static final String CERT_VERSION = PREFIX + "cert_version";
  /** Required. The path of the certificate file in PEM format. */
  public static final String CERT_PATH = PREFIX + "cert_path";
  /** Required if cert_path is empty. PEM-encoded certificate data. */
  public static final String CERT_PEM = PREFIX + "cert_pem";
  /** Required. The path of a corresponding private key file in PEM format to the certificate. */
  public static final String PRIVATE_KEY_PATH = PREFIX + "private_key_path";
  /** Required if private_key_path is empty. PEM-encoded private key data. */
  public static final String PRIVATE_KEY_PEM = PREFIX + "private_key_pem";
  /** Optional. A flag to enable TLS communication for Ledger (false by default). */
  public static final String TLS_ENABLED = PREFIX + "tls.enabled";
  /**
   * Optional. A custom CA root certificate (file path) for TLS communication for Ledger. If the
   * issuing certificate authority is known to the client, it can be empty.
   */
  public static final String TLS_CA_ROOT_CERT_PATH = PREFIX + "tls.ca_root_cert_path";
  /**
   * Optional. A custom CA root certificate (PEM data) for TLS communication for Ledger. If the
   * issuing certificate authority is known to the client, it can be empty.
   */
  public static final String TLS_CA_ROOT_CERT_PEM = PREFIX + "tls.ca_root_cert_pem";
  /**
   * Optional. An authorization credential for Ledger. (e.g. authorization: Bearer token) If this is
   * given, clients will add "authorization: [credential]" http/2 header.
   */
  public static final String AUTHORIZATION_CREDENTIAL = PREFIX + "authorization.credential";
  /**
   * Optional. A client mode. CLIENT OR INTERMEDIARY. CLIENT by default. In INTERMEDIARY mode, this
   * client receives a signed serialized request from another client, and sends it to a server.
   */
  public static final String MODE = PREFIX + "mode";
  /**
   * Experimental. Proxy server. Proxy feature is deprecated and will be removed in release 4.0.0.
   */
  @Deprecated public static final String PROXY_SERVER = PREFIX + "proxy.server";
  /** Optional. A flag to enable auditor (false by default). */
  public static final String AUDITOR_ENABLED = PREFIX + "auditor.enabled";
  /**
   * Optional. A hostname or an IP address of the auditor ("localhost" by default). It assumes that
   * there is a single endpoint that is given by DNS or a load balancer.
   */
  public static final String AUDITOR_HOST = PREFIX + "auditor.host";
  /** Optional. A port number of the auditor (40051 by default). */
  public static final String AUDITOR_PORT = PREFIX + "auditor.port";
  /** Optional. A port number of the auditor for privileged services (40052 by default). */
  public static final String AUDITOR_PRIVILEGED_PORT = PREFIX + "auditor.privileged_port";
  /** Optional. A flag to enable TLS communication for Auditor (false by default). */
  public static final String AUDITOR_TLS_ENABLED = PREFIX + "auditor.tls.enabled";
  /**
   * Optional. A custom CA root certificate (file path) for TLS communication for Auditor. If the
   * issuing certificate authority is known to the client, it can be empty.
   */
  public static final String AUDITOR_TLS_CA_ROOT_CERT_PATH =
      PREFIX + "auditor.tls.ca_root_cert_path";
  /**
   * Optional. A custom CA root certificate (PEM data) for TLS communication for Auditor. If the
   * issuing certificate authority is known to the client, it can be empty.
   */
  public static final String AUDITOR_TLS_CA_ROOT_CERT_PEM = PREFIX + "auditor.tls.ca_root_cert_pem";
  /**
   * Optional. An authorization credential for Auditor. (e.g. authorization: Bearer token) If this
   * is given, clients will add "authorization: [credential]" http/2 header.
   */
  public static final String AUDITOR_AUTHORIZATION_CREDENTIAL =
      PREFIX + "auditor.authorization.credential";
  /**
   * Optional. The ID of ValidateLedger contract ("validate-ledger" by default). It is used for the
   * linearizable validation.
   */
  public static final String AUDITOR_LINEARIZABLE_VALIDATION_CONTRACT_ID =
      PREFIX + "auditor.linearizable_validation.contract_id";

  static final String DEFAULT_SERVER_HOST = "localhost";
  static final int DEFAULT_SERVER_PORT = 50051;
  static final int DEFAULT_SERVER_PRIVILEGED_PORT = 50052;
  static final int DEFAULT_CERT_VERSION = 1;
  static final boolean DEFAULT_TLS_ENABLED = false;

  private final Properties props;
  private String serverHost = DEFAULT_SERVER_HOST;
  private int serverPort = DEFAULT_SERVER_PORT;
  private int serverPrivilegedPort = DEFAULT_SERVER_PRIVILEGED_PORT;
  private String certHolderId;
  private int certVersion = DEFAULT_CERT_VERSION;
  private String cert;
  private String privateKey;
  private boolean isTlsEnabled = DEFAULT_TLS_ENABLED;
  private String tlsCaRootCert;
  private String authorizationCredential;
  private ClientMode clientMode = ClientMode.CLIENT;
  private Server proxyServer;
  private boolean isAuditorEnabled = false;
  private String auditorHost = "localhost";
  private int auditorPort = 40051;
  private int auditorPrivilegedPort = 40052;
  private boolean isAuditorTlsEnabled = false;
  private String auditorTlsCaRootCert;
  private String auditorAuthorizationCredential;
  private String auditorLinearizableValidationContractId = "validate-ledger";
  private IdentityConfig identityConfig;
  private TargetConfig ledgerTargetConfig;
  private TargetConfig auditorTargetConfig;

  public ClientConfig(File propertiesFile) throws IOException {
    try (FileInputStream stream = new FileInputStream(propertiesFile)) {
      props = new Properties();
      props.load(stream);
    }
    load();
  }

  public ClientConfig(InputStream stream) throws IOException {
    props = new Properties();
    props.load(stream);
    load();
  }

  public ClientConfig(Properties properties) throws IOException {
    props = new Properties();
    props.putAll(properties);
    load();
  }

  public IdentityConfig getIdentityConfig() {
    return identityConfig;
  }

  @Nonnull
  public TargetConfig getLedgerTargetConfig() {
    return ledgerTargetConfig;
  }

  @Nullable
  public TargetConfig getAuditorTargetConfig() {
    return auditorTargetConfig;
  }

  public ClientMode getClientMode() {
    return clientMode;
  }

  /** Proxy feature is deprecated and will be removed in release 4.0.0. */
  @Deprecated
  public Server getProxyServer() {
    return proxyServer;
  }

  public boolean isAuditorEnabled() {
    return isAuditorEnabled;
  }

  public String getAuditorLinearizableValidationContractId() {
    return auditorLinearizableValidationContractId;
  }

  private void load() {
    if (PropertiesUtil.isNonEmpty(props, SERVER_HOST)) {
      serverHost = props.getProperty(SERVER_HOST);
    }
    if (PropertiesUtil.isNonEmpty(props, SERVER_PORT)) {
      serverPort = Integer.parseInt(props.getProperty(SERVER_PORT));
    }
    if (PropertiesUtil.isNonEmpty(props, SERVER_PRIVILEGED_PORT)) {
      serverPrivilegedPort = Integer.parseInt(props.getProperty(SERVER_PRIVILEGED_PORT));
    }
    if (PropertiesUtil.isNonEmpty(props, MODE)) {
      clientMode = ClientMode.valueOf(props.getProperty(MODE));
    }
    if (clientMode.equals(ClientMode.CLIENT)) {
      checkArgument(
          PropertiesUtil.isNonEmpty(props, CERT_HOLDER_ID),
          CERT_HOLDER_ID + " is missing but required.");
      certHolderId = props.getProperty(CERT_HOLDER_ID);
      if (PropertiesUtil.isNonEmpty(props, CERT_VERSION)) {
        certVersion = Integer.parseInt(props.getProperty(CERT_VERSION));
      }
      cert = PropertiesUtil.readFromStringOrFile(props, CERT_PEM, CERT_PATH);
      checkArgument(cert != null, "either " + CERT_PEM + " or " + CERT_PATH + " is required.");
      privateKey = PropertiesUtil.readFromStringOrFile(props, PRIVATE_KEY_PEM, PRIVATE_KEY_PATH);
      checkArgument(
          privateKey != null,
          "either " + PRIVATE_KEY_PEM + " or " + PRIVATE_KEY_PATH + " is required.");
    }
    if (PropertiesUtil.isNonEmpty(props, TLS_ENABLED)) {
      isTlsEnabled = Boolean.parseBoolean(props.getProperty(TLS_ENABLED));
    }
    tlsCaRootCert =
        PropertiesUtil.readFromStringOrFile(props, TLS_CA_ROOT_CERT_PEM, TLS_CA_ROOT_CERT_PATH);
    authorizationCredential = props.getProperty(AUTHORIZATION_CREDENTIAL);
    if (PropertiesUtil.isNonEmpty(props, PROXY_SERVER)) {
      proxyServer = parseServers(props.getProperty(PROXY_SERVER)).get(0);
    }
    if (PropertiesUtil.isNonEmpty(props, AUDITOR_ENABLED)) {
      isAuditorEnabled = Boolean.parseBoolean(props.getProperty(AUDITOR_ENABLED));
    }
    if (isAuditorEnabled) {
      if (PropertiesUtil.isNonEmpty(props, AUDITOR_HOST)) {
        auditorHost = props.getProperty(AUDITOR_HOST);
      }
      if (PropertiesUtil.isNonEmpty(props, AUDITOR_PORT)) {
        auditorPort = Integer.parseInt(props.getProperty(AUDITOR_PORT));
      }
      if (PropertiesUtil.isNonEmpty(props, AUDITOR_PRIVILEGED_PORT)) {
        auditorPrivilegedPort = Integer.parseInt(props.getProperty(AUDITOR_PRIVILEGED_PORT));
      }
      if (PropertiesUtil.isNonEmpty(props, AUDITOR_TLS_ENABLED)) {
        isAuditorTlsEnabled = Boolean.parseBoolean(props.getProperty(AUDITOR_TLS_ENABLED));
      }
      auditorTlsCaRootCert =
          PropertiesUtil.readFromStringOrFile(
              props, AUDITOR_TLS_CA_ROOT_CERT_PEM, AUDITOR_TLS_CA_ROOT_CERT_PATH);
      auditorAuthorizationCredential = props.getProperty(AUDITOR_AUTHORIZATION_CREDENTIAL);
      if (PropertiesUtil.isNonEmpty(props, AUDITOR_LINEARIZABLE_VALIDATION_CONTRACT_ID)) {
        auditorLinearizableValidationContractId =
            props.getProperty(AUDITOR_LINEARIZABLE_VALIDATION_CONTRACT_ID);
      }
    }

    identityConfig = createIdentityConfig();
    ledgerTargetConfig = createLedgerTargetConfig();
    auditorTargetConfig = createAuditorTargetConfig();
  }

  @Nonnull
  private IdentityConfig createIdentityConfig() {
    return IdentityConfig.newBuilder()
        .certHolderId(certHolderId)
        .certVersion(certVersion)
        .cert(cert)
        .privateKey(privateKey)
        .build();
  }

  @Nonnull
  private TargetConfig createLedgerTargetConfig() {
    return TargetConfig.newBuilder()
        .host(serverHost)
        .port(serverPort)
        .privilegedPort(serverPrivilegedPort)
        .tlsEnabled(isTlsEnabled)
        .tlsCaRootCert(tlsCaRootCert)
        .authorizationCredential(authorizationCredential)
        .build();
  }

  @Nullable
  private TargetConfig createAuditorTargetConfig() {
    if (!isAuditorEnabled) {
      return null;
    }
    return TargetConfig.newBuilder()
        .host(auditorHost)
        .port(auditorPort)
        .privilegedPort(auditorPrivilegedPort)
        .tlsEnabled(isAuditorTlsEnabled)
        .tlsCaRootCert(auditorTlsCaRootCert)
        .authorizationCredential(auditorAuthorizationCredential)
        .build();
  }

  private List parseServers(String line) {
    List list = new ArrayList<>();

    for (String item : Splitter.on(',').split(line)) {
      List elements = Splitter.on(':').splitToList(item);
      list.add(new Server(elements.get(0), Integer.parseInt(elements.get(1))));
    }
    return list;
  }

  public static class Server {
    private final String host;
    private final int port;

    public Server(String host, int port) {
      this.host = host;
      this.port = port;
    }

    public String getHost() {
      return host;
    }

    public int getPort() {
      return port;
    }
  }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy