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

io.fabric8.kubernetes.client.utils.HttpClientUtils Maven / Gradle / Ivy

/**
 * Copyright (C) 2015 Red Hat, Inc.
 *
 * 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 io.fabric8.kubernetes.client.utils;

import io.fabric8.kubernetes.client.Config;
import io.fabric8.kubernetes.client.KubernetesClientException;
import io.fabric8.kubernetes.client.http.BasicBuilder;
import io.fabric8.kubernetes.client.http.HttpClient;
import io.fabric8.kubernetes.client.http.HttpHeaders;
import io.fabric8.kubernetes.client.http.Interceptor;
import io.fabric8.kubernetes.client.internal.SSLUtils;
import io.fabric8.kubernetes.client.okhttp.OkHttpClientFactory;
import io.fabric8.kubernetes.client.okhttp.OkHttpClientImpl;
import okhttp3.OkHttpClient;
import okhttp3.OkHttpClient.Builder;

import javax.net.ssl.KeyManager;
import javax.net.ssl.SSLContext;
import javax.net.ssl.TrustManager;

import java.net.InetSocketAddress;
import java.net.MalformedURLException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import java.util.LinkedHashMap;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.function.Consumer;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

public class HttpClientUtils {
  
  public static final String HEADER_INTERCEPTOR = "HEADER";
  
  private HttpClientUtils() { }

  private static Pattern VALID_IPV4_PATTERN = null;
  public static final String ipv4Pattern = "(http:\\/\\/|https:\\/\\/)?(([01]?\\d\\d?|2[0-4]\\d|25[0-5])\\.){3}([01]?\\d\\d?|2[0-4]\\d|25[0-5])(\\/[0-9]\\d|1[0-9]\\d|2[0-9]\\d|3[0-2]\\d)?";
  protected static final String KUBERNETES_BACKWARDS_COMPATIBILITY_INTERCEPTOR_DISABLE = "kubernetes.backwardsCompatibilityInterceptor.disable";

  static {
    try {
      VALID_IPV4_PATTERN = Pattern.compile(ipv4Pattern, Pattern.CASE_INSENSITIVE);
    } catch (PatternSyntaxException e) {
      throw KubernetesClientException.launderThrowable("Unable to compile ipv4address pattern.", e);
    }
  }
  
  /**
   * Creates an HTTP client configured to access the Kubernetes API.
   * @param config Kubernetes API client config
   * @param additionalConfig a consumer that allows overriding HTTP client properties
   * @return returns an HTTP client
   * @deprecated subclass {@link OkHttpClientFactory} and implement the additionalConfig method
   */
  @Deprecated
  public static OkHttpClientImpl createHttpClient(final Config config, final Consumer additionalConfig) {
    return new OkHttpClientFactory() {
      @Override
      protected void additionalConfig(Builder builder) {
        if (additionalConfig != null) {
          additionalConfig.accept(builder);
        }
      }
    }.createHttpClient(config);
  }

    public static URL getProxyUrl(Config config) throws MalformedURLException {
        URL master = new URL(config.getMasterUrl());
        String host = master.getHost();
        if (config.getNoProxy() != null) {
	        for (String noProxy : config.getNoProxy()) {
            if (isIpAddress(noProxy)) {
              if (new IpAddressMatcher(noProxy).matches(host)) {
                return null;
              }
            } else {
              if (host.contains(noProxy)) {
                return null;
              }
            }
	        }
        }
        String proxy = config.getHttpsProxy();
        if (master.getProtocol().equals("http")) {
            proxy = config.getHttpProxy();
        }
        if (proxy != null) {
            URL proxyUrl = new URL(proxy);
            if (proxyUrl.getPort() < 0) {
              throw new IllegalArgumentException("Failure in creating proxy URL. Proxy port is required!");
            }
            return proxyUrl;
        }
        return null;
    }

    private static boolean isIpAddress(String ipAddress) {
        Matcher ipMatcher = VALID_IPV4_PATTERN.matcher(ipAddress);
        return ipMatcher.matches();
    }

  public static Map createApplicableInterceptors(Config config, HttpClient.Factory factory) {
    Map interceptors = new LinkedHashMap<>();
    
    // Header Interceptor
    interceptors.put(HEADER_INTERCEPTOR, new Interceptor() {
      
      @Override
      public void before(BasicBuilder builder, HttpHeaders headers) {
        if (Utils.isNotNullOrEmpty(config.getUsername()) && Utils.isNotNullOrEmpty(config.getPassword())) {
          builder.header("Authorization", basicCredentials(config.getUsername(), config.getPassword()));
        } else if (Utils.isNotNullOrEmpty(config.getOauthToken())) {
          builder.header("Authorization", "Bearer " + config.getOauthToken());
        }
        if (config.getCustomHeaders() != null && !config.getCustomHeaders().isEmpty()) {
          for (Map.Entry entry : config.getCustomHeaders().entrySet()) {
            builder.header(entry.getKey(),entry.getValue());
          }
        }
        if (config.getUserAgent() != null && !config.getUserAgent().isEmpty()) {
          builder.setHeader("User-Agent", config.getUserAgent());
        }
      }
    });
    // Impersonator Interceptor
    interceptors.put(ImpersonatorInterceptor.NAME, new ImpersonatorInterceptor(config));
    // Token Refresh Interceptor
    interceptors.put(TokenRefreshInterceptor.NAME, new TokenRefreshInterceptor(config, factory));
    // Backwards Compatibility Interceptor
    String shouldDisableBackwardsCompatibilityInterceptor = Utils.getSystemPropertyOrEnvVar(KUBERNETES_BACKWARDS_COMPATIBILITY_INTERCEPTOR_DISABLE, "false");
    if (!Boolean.parseBoolean(shouldDisableBackwardsCompatibilityInterceptor)) {
      interceptors.put(BackwardsCompatibilityInterceptor.NAME, new BackwardsCompatibilityInterceptor());
    }

    return interceptors;
  }
  
  public static String basicCredentials(String username, String password) {
    String usernameAndPassword = username + ":" + password;
    String encoded = Base64.getEncoder().encodeToString(usernameAndPassword.getBytes(StandardCharsets.ISO_8859_1));
    return "Basic " + encoded;
  }

  public static HttpClient createHttpClient(Config config) {
    // TODO: replace with reflection / service load and factory interface
    return new OkHttpClientFactory().createHttpClient(config);
  }
  
  public static void applyCommonConfiguration(Config config, HttpClient.Builder builder, HttpClient.Factory factory) {
    builder.followAllRedirects();
    
    if (config.getConnectionTimeout() > 0) {
      builder.connectTimeout(config.getConnectionTimeout(), TimeUnit.MILLISECONDS);
    }

    if (config.getRequestTimeout() > 0) {
      builder.readTimeout(config.getRequestTimeout(), TimeUnit.MILLISECONDS);
    }
    
    if (config.isHttp2Disable()) {
      builder.preferHttp11();
    }
    
    try {
      
      // Only check proxy if it's a full URL with protocol
      if (config.getMasterUrl().toLowerCase(Locale.ROOT).startsWith(Config.HTTP_PROTOCOL_PREFIX)
          || config.getMasterUrl().startsWith(Config.HTTPS_PROTOCOL_PREFIX)) {
        try {
          URL proxyUrl = HttpClientUtils.getProxyUrl(config);
          if (proxyUrl != null) {
            builder.proxyAddress(new InetSocketAddress(proxyUrl.getHost(), proxyUrl.getPort()));

            if (config.getProxyUsername() != null) {
              builder.proxyAuthorization(basicCredentials(config.getProxyUsername(), config.getProxyPassword()));
            }
          } else {
            builder.proxyAddress(null);
          }
        } catch (MalformedURLException e) {
          throw new KubernetesClientException("Invalid proxy server configuration", e);
        }
      }
      
      TrustManager[] trustManagers = SSLUtils.trustManagers(config);
      KeyManager[] keyManagers = SSLUtils.keyManagers(config);
  
      SSLContext sslContext = SSLUtils.sslContext(keyManagers, trustManagers);
      builder.sslContext(sslContext, trustManagers);
      
      if (config.getTlsVersions() != null && config.getTlsVersions().length > 0) {
        builder.tlsVersions(config.getTlsVersions());
      }
      
    } catch (Exception e) {
      throw KubernetesClientException.launderThrowable(e);
    }
    HttpClientUtils.createApplicableInterceptors(config, factory).forEach(builder::addOrReplaceInterceptor);
  }
  
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy