org.sonatype.nexus.httpclient.config.ConfigurationCustomizer.java Source code

Java tutorial

Introduction

Here is the source code for org.sonatype.nexus.httpclient.config.ConfigurationCustomizer.java

Source

/*
 * Sonatype Nexus (TM) Open Source Version
 * Copyright (c) 2008-present Sonatype, Inc.
 * All rights reserved. Includes the third-party code listed at http://links.sonatype.com/products/nexus/oss/attributions.
 *
 * This program and the accompanying materials are made available under the terms of the Eclipse Public License Version 1.0,
 * which accompanies this distribution and is available at http://www.eclipse.org/legal/epl-v10.html.
 *
 * Sonatype Nexus (TM) Professional Version is available from Sonatype, Inc. "Sonatype" and "Sonatype Nexus" are trademarks
 * of Sonatype, Inc. Apache Maven is a trademark of the Apache Software Foundation. M2eclipse is a trademark of the
 * Eclipse Foundation. All other trademarks are the property of their respective owners.
 */
package org.sonatype.nexus.httpclient.config;

import java.net.Authenticator;
import java.net.PasswordAuthentication;
import java.util.Arrays;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.regex.Pattern;
import java.util.regex.PatternSyntaxException;

import javax.annotation.Nullable;

import org.sonatype.goodies.common.ComponentSupport;
import org.sonatype.nexus.common.text.Strings2;
import org.sonatype.nexus.httpclient.HttpClientPlan;
import org.sonatype.nexus.httpclient.SSLContextSelector;
import org.sonatype.nexus.httpclient.internal.NexusHttpRoutePlanner;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Function;
import com.google.common.base.Joiner;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.NTCredentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.config.CookieSpecs;
import org.apache.http.impl.client.StandardHttpRequestRetryHandler;

import static com.google.common.base.Preconditions.checkNotNull;
import static com.google.common.base.Preconditions.checkState;
import static org.apache.http.client.config.AuthSchemes.BASIC;
import static org.apache.http.client.config.AuthSchemes.DIGEST;
import static org.apache.http.client.config.AuthSchemes.NTLM;
import static org.sonatype.nexus.httpclient.HttpSchemes.HTTP;
import static org.sonatype.nexus.httpclient.HttpSchemes.HTTPS;

/**
 * Applies {@link HttpClientConfiguration} to {@link HttpClientPlan}.
 *
 * @since 3.0
 */
public class ConfigurationCustomizer extends ComponentSupport implements HttpClientPlan.Customizer {
    /**
     * Simple reusable function that converts "glob-like" expressions to regexp.
     */
    private static final Function<String, String> GLOB_STRING_TO_REGEXP_STRING = new Function<String, String>() {
        @Override
        public String apply(final String input) {
            return "(" + input.toLowerCase(Locale.US).replaceAll("\\.", "\\\\.").replaceAll("\\*", ".*?")
                    .replaceAll("\\[", "\\\\[").replaceAll("\\]", "\\\\]") + ")";
        }
    };

    static {
        /**
         * Install custom {@link Authenticator} for proxy.
         */
        Authenticator.setDefault(new Authenticator() {
            @Override
            protected PasswordAuthentication getPasswordAuthentication() {
                if (getRequestorType() == RequestorType.PROXY) {
                    String prot = getRequestingProtocol().toLowerCase();
                    String host = System.getProperty(prot + ".proxyHost", "");
                    String port = System.getProperty(prot + ".proxyPort", "80");
                    String user = System.getProperty(prot + ".proxyUser", "");
                    String password = System.getProperty(prot + ".proxyPassword", "");

                    if (getRequestingHost().equalsIgnoreCase(host)) {
                        if (Integer.parseInt(port) == getRequestingPort()) {
                            // Seems to be OK.
                            return new PasswordAuthentication(user, password.toCharArray());
                        }
                    }
                }
                return null;
            }
        });
    }

    private final HttpClientConfiguration configuration;

    public ConfigurationCustomizer(final HttpClientConfiguration configuration) {
        this.configuration = checkNotNull(configuration);
    }

    @Override
    public void customize(final HttpClientPlan plan) {
        checkNotNull(plan);

        if (configuration.getConnection() != null) {
            apply(configuration.getConnection(), plan);
        }
        if (configuration.getProxy() != null) {
            apply(configuration.getProxy(), plan);
        }
        if (configuration.getAuthentication() != null) {
            apply(configuration.getAuthentication(), plan, null);
        }
    }

    /**
     * Apply connection configuration to plan.
     */
    private void apply(final ConnectionConfiguration connection, final HttpClientPlan plan) {
        if (connection.getTimeout() != null) {
            int timeout = connection.getTimeout().toMillisI();
            plan.getSocket().setSoTimeout(timeout);
            plan.getRequest().setConnectTimeout(timeout);
            plan.getRequest().setSocketTimeout(timeout);
        }

        if (connection.getMaximumRetries() != null) {
            plan.getClient()
                    .setRetryHandler(new StandardHttpRequestRetryHandler(connection.getMaximumRetries(), false));
        }

        if (connection.getUserAgentSuffix() != null) {
            checkState(plan.getUserAgentBase() != null, "Default User-Agent not set");
            plan.setUserAgentSuffix(connection.getUserAgentSuffix());
        }

        if (Boolean.TRUE.equals(connection.getUseTrustStore())) {
            plan.getAttributes().put(SSLContextSelector.USE_TRUST_STORE, Boolean.TRUE);
        }

        if (Boolean.TRUE.equals(connection.getEnableCircularRedirects())) {
            plan.getRequest().setCircularRedirectsAllowed(true);
        }

        if (Boolean.TRUE.equals(connection.getEnableCookies())) {
            plan.getRequest().setCookieSpec(CookieSpecs.DEFAULT);
        }
    }

    /**
     * Apply proxy-server configuration to plan.
     */
    private void apply(final ProxyConfiguration proxy, final HttpClientPlan plan) {
        // HTTP proxy
        ProxyServerConfiguration http = proxy.getHttp();
        if (http != null && http.isEnabled()) {
            HttpHost host = new HttpHost(http.getHost(), http.getPort());
            if (http.getAuthentication() != null) {
                apply(http.getAuthentication(), plan, host);
            }
        }

        // HTTPS proxy
        ProxyServerConfiguration https = proxy.getHttps();
        if (https != null && https.isEnabled()) {
            HttpHost host = new HttpHost(https.getHost(), https.getPort());
            if (https.getAuthentication() != null) {
                apply(https.getAuthentication(), plan, host);
            }
        }
        plan.getClient().setRoutePlanner(createRoutePlanner(proxy));
    }

    /**
     * Creates instance of {@link NexusHttpRoutePlanner} from passed in configuration, never {@code null}.
     */
    @VisibleForTesting
    NexusHttpRoutePlanner createRoutePlanner(final ProxyConfiguration proxy) {
        Map<String, HttpHost> proxies = new HashMap<>(2);

        // HTTP proxy
        ProxyServerConfiguration http = proxy.getHttp();
        if (http != null && http.isEnabled()) {
            HttpHost host = new HttpHost(http.getHost(), http.getPort());
            proxies.put(HTTP, host);
            proxies.put(HTTPS, host);
        }

        // HTTPS proxy
        ProxyServerConfiguration https = proxy.getHttps();
        if (https != null && https.isEnabled()) {
            HttpHost host = new HttpHost(https.getHost(), https.getPort());
            proxies.put(HTTPS, host);
        }

        // Non-proxy hosts (Java http.nonProxyHosts formatted glob-like patterns converted to single Regexp expression)
        LinkedHashSet<String> patterns = new LinkedHashSet<>();
        if (proxy.getNonProxyHosts() != null) {
            patterns.addAll(Arrays.asList(proxy.getNonProxyHosts()));
        }
        String nonProxyPatternString = Joiner.on("|")
                .join(Iterables.transform(patterns, GLOB_STRING_TO_REGEXP_STRING));
        Pattern nonProxyPattern = null;
        if (!Strings2.isBlank(nonProxyPatternString)) {
            try {
                nonProxyPattern = Pattern.compile(nonProxyPatternString, Pattern.CASE_INSENSITIVE);
            } catch (PatternSyntaxException e) {
                log.warn("Invalid non-proxy host regex: {}, using defaults", nonProxyPatternString, e);
            }
        }
        return new NexusHttpRoutePlanner(proxies, nonProxyPattern);
    }

    /**
     * Apply authentication configuration to plan.
     */
    private void apply(final AuthenticationConfiguration authentication, final HttpClientPlan plan,
            @Nullable final HttpHost proxyHost) {
        Credentials credentials;
        List<String> authSchemes;

        if (authentication instanceof UsernameAuthenticationConfiguration) {
            UsernameAuthenticationConfiguration auth = (UsernameAuthenticationConfiguration) authentication;
            authSchemes = ImmutableList.of(DIGEST, BASIC);
            credentials = new UsernamePasswordCredentials(auth.getUsername(), auth.getPassword());
        } else if (authentication instanceof NtlmAuthenticationConfiguration) {
            NtlmAuthenticationConfiguration auth = (NtlmAuthenticationConfiguration) authentication;
            authSchemes = ImmutableList.of(NTLM, DIGEST, BASIC);
            credentials = new NTCredentials(auth.getUsername(), auth.getPassword(), auth.getHost(),
                    auth.getDomain());
        } else {
            throw new IllegalArgumentException("Unsupported authentication configuration: " + authentication);
        }

        if (proxyHost != null) {
            plan.addCredentials(new AuthScope(proxyHost), credentials);
            plan.getRequest().setProxyPreferredAuthSchemes(authSchemes);
        } else {
            plan.addCredentials(AuthScope.ANY, credentials);
            plan.getRequest().setTargetPreferredAuthSchemes(authSchemes);
        }
    }
}