Package org.sonatype.nexus.client.rest.jersey

Source Code of org.sonatype.nexus.client.rest.jersey.NexusClientFactoryImpl

/*
* Sonatype Nexus (TM) Open Source Version
* Copyright (c) 2007-2014 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.client.rest.jersey;

import java.net.URI;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;
import java.util.List;

import javax.ws.rs.core.MediaType;

import org.sonatype.nexus.client.core.Condition;
import org.sonatype.nexus.client.core.NexusClient;
import org.sonatype.nexus.client.core.condition.NexusStatusConditions;
import org.sonatype.nexus.client.core.spi.SubsystemProvider;
import org.sonatype.nexus.client.internal.rest.NexusXStreamFactory;
import org.sonatype.nexus.client.internal.rest.XStreamXmlProvider;
import org.sonatype.nexus.client.internal.util.Version;
import org.sonatype.nexus.client.rest.AuthenticationInfo;
import org.sonatype.nexus.client.rest.BaseUrl;
import org.sonatype.nexus.client.rest.ConnectionInfo;
import org.sonatype.nexus.client.rest.NexusClientFactory;
import org.sonatype.nexus.client.rest.ProxyInfo;
import org.sonatype.nexus.client.rest.UsernamePasswordAuthenticationInfo;
import org.sonatype.sisu.siesta.client.filters.RequestFilters;

import com.google.common.base.Preconditions;
import com.google.common.base.Throwables;
import com.sun.jersey.api.client.ClientHandlerException;
import com.sun.jersey.api.client.filter.LoggingFilter;
import com.sun.jersey.client.apache4.ApacheHttpClient4;
import com.sun.jersey.client.apache4.config.ApacheHttpClient4Config;
import com.sun.jersey.client.apache4.config.DefaultApacheHttpClient4Config;
import com.thoughtworks.xstream.XStream;
import org.apache.http.HttpHost;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CredentialsProvider;
import org.apache.http.conn.scheme.Scheme;
import org.apache.http.conn.ssl.AllowAllHostnameVerifier;
import org.apache.http.conn.ssl.BrowserCompatHostnameVerifier;
import org.apache.http.conn.ssl.SSLSocketFactory;
import org.apache.http.conn.ssl.StrictHostnameVerifier;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.conn.ssl.TrustStrategy;
import org.apache.http.conn.ssl.X509HostnameVerifier;
import org.apache.http.impl.client.BasicCredentialsProvider;
import org.apache.http.impl.conn.PoolingClientConnectionManager;
import org.apache.http.impl.conn.SchemeRegistryFactory;
import org.apache.http.params.CoreProtocolPNames;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import static com.sun.jersey.api.client.config.ClientConfig.PROPERTY_FOLLOW_REDIRECTS;
import static com.sun.jersey.client.apache4.config.ApacheHttpClient4Config.PROPERTY_CREDENTIALS_PROVIDER;
import static com.sun.jersey.client.apache4.config.ApacheHttpClient4Config.PROPERTY_PREEMPTIVE_BASIC_AUTHENTICATION;
import static com.sun.jersey.client.apache4.config.ApacheHttpClient4Config.PROPERTY_PROXY_PASSWORD;
import static com.sun.jersey.client.apache4.config.ApacheHttpClient4Config.PROPERTY_PROXY_URI;
import static com.sun.jersey.client.apache4.config.ApacheHttpClient4Config.PROPERTY_PROXY_USERNAME;
import static org.apache.http.conn.params.ConnRoutePNames.DEFAULT_PROXY;

/**
* Jersey based {@link NexusClientFactory}.
*
* @since 2.7
*/
public class NexusClientFactoryImpl
    implements NexusClientFactory
{

  private static final Logger LOG = LoggerFactory.getLogger(NexusClientFactoryImpl.class);

  /**
   * Modified "content-type" used by Nexus Client: it enforces body encoding too for UTF8.
   */
  private static final MediaType APPLICATION_XML_UTF8_TYPE = MediaType.valueOf("application/xml; charset=UTF-8");

  private final Condition connectionCondition;

  private final List<SubsystemProvider> subsystemProviders;

  public NexusClientFactoryImpl(final List<SubsystemProvider> subsystemProviders) {
    this(NexusStatusConditions.anyModern(), subsystemProviders);
  }

  public NexusClientFactoryImpl(final Condition connectionCondition,
                                final List<SubsystemProvider> subsystemProviders)
  {
    this.connectionCondition = Preconditions.checkNotNull(connectionCondition, "connectionCondition");
    this.subsystemProviders = Preconditions.checkNotNull(subsystemProviders, "subsystemProviders");
  }

  @Override
  public final NexusClient createFor(final BaseUrl baseUrl) {
    return createFor(baseUrl, null);
  }

  @Override
  public final NexusClient createFor(final BaseUrl baseUrl, final AuthenticationInfo authenticationInfo) {
    return createFor(new ConnectionInfo(baseUrl, authenticationInfo, null));
  }

  @Override
  public final NexusClient createFor(final ConnectionInfo connectionInfo) {
    // we are java2java client, so we use XML instead of JSON, as
    // some current Nexus are one way only! So, we fix for XML
    final XStream xstream = new NexusXStreamFactory().createAndConfigureForXml();

    // we use XML for communication (unlike web browsers do, for which JSON makes more sense)
    return new JerseyNexusClient(
        connectionCondition,
        subsystemProviders,
        connectionInfo,
        xstream,
        doCreateHttpClientFor(connectionInfo, xstream),
        APPLICATION_XML_UTF8_TYPE
    );
  }

  protected ApacheHttpClient4 doCreateHttpClientFor(final ConnectionInfo connectionInfo, final XStream xstream) {
    final ApacheHttpClient4Config config = new DefaultApacheHttpClient4Config();
    config.getSingletons().add(new XStreamXmlProvider(xstream, APPLICATION_XML_UTF8_TYPE));
    // set _real_ URL for baseUrl, and not a redirection (typically http instead of https)
    config.getProperties().put(PROPERTY_FOLLOW_REDIRECTS, Boolean.FALSE);

    applyAuthenticationIfAny(connectionInfo, config);
    applyProxyIfAny(connectionInfo, config);

    // obey JSSE defined system properties
    config.getProperties().put(ApacheHttpClient4Config.PROPERTY_CONNECTION_MANAGER,
        new PoolingClientConnectionManager(SchemeRegistryFactory.createSystemDefault()));

    final ApacheHttpClient4 client = ApacheHttpClient4.create(config);

    // set UA
    client.getClientHandler().getHttpClient().getParams().setParameter(
        CoreProtocolPNames.USER_AGENT, "Nexus-Client/" + discoverClientVersion()
    );

    // "tweak" HTTPS scheme as requested
    final TrustStrategy trustStrategy;
    switch (connectionInfo.getSslCertificateValidation()) {
      case NONE:
        trustStrategy = new TrustStrategy()
        {
          @Override
          public boolean isTrusted(final X509Certificate[] chain, final String authType) throws CertificateException {
            return true;
          }
        };
        break;
      case LAX:
        trustStrategy = new TrustSelfSignedStrategy();
        break;
      default:
        trustStrategy = null;
    }

    final X509HostnameVerifier hostnameVerifier;
    switch (connectionInfo.getSslCertificateHostnameValidation()) {
      case NONE:
        hostnameVerifier = new AllowAllHostnameVerifier();
        break;
      case STRICT:
        hostnameVerifier = new StrictHostnameVerifier();
        break;
      default:
        hostnameVerifier = new BrowserCompatHostnameVerifier();
    }

    try {
      final SSLSocketFactory ssf = new SSLSocketFactory(trustStrategy, hostnameVerifier);
      final Scheme tweakedHttpsScheme = new Scheme("https", 443, ssf);
      client.getClientHandler().getHttpClient().getConnectionManager().getSchemeRegistry().register(tweakedHttpsScheme);
    }
    catch (Exception e) {
      Throwables.propagate(e);
    }

    // NXCM-4547 JERSEY-1293 Enforce proxy setting on httpclient
    enforceProxyUri(config, client);

    if (LOG.isDebugEnabled()) {
      client.addFilter(new LoggingFilter());
    }

    client.addFilter(new RequestFilters());

    return client;
  }

  protected String discoverClientVersion() {
    return Version.readVersion("META-INF/maven/org.sonatype.nexus/nexus-client-core/pom.properties", "unknown");
  }

  // ==

  /**
   * NXCM-4547 JERSEY-1293 Enforce proxy setting on httpclient
   * <p/>
   * Revisit for jersey 1.13.
   */
  private void enforceProxyUri(final ApacheHttpClient4Config config, final ApacheHttpClient4 client) {
    final Object proxyProperty = config.getProperties().get(PROPERTY_PROXY_URI);
    if (proxyProperty != null) {
      final URI uri = getProxyUri(proxyProperty);
      final HttpHost proxy = new HttpHost(uri.getHost(), uri.getPort(), uri.getScheme());
      client.getClientHandler().getHttpClient().getParams().setParameter(DEFAULT_PROXY, proxy);
    }
  }

  private static URI getProxyUri(final Object proxy) {
    if (proxy instanceof URI) {
      return (URI) proxy;
    }
    else if (proxy instanceof String) {
      return URI.create((String) proxy);
    }
    else {
      throw new ClientHandlerException("The proxy URI (" + PROPERTY_PROXY_URI +
          ") property MUST be an instance of String or URI");
    }
  }

  // ==

  protected void applyAuthenticationIfAny(final ConnectionInfo connectionInfo, ApacheHttpClient4Config config) {
    if (connectionInfo.getAuthenticationInfo() != null) {
      if (connectionInfo.getAuthenticationInfo() instanceof UsernamePasswordAuthenticationInfo) {
        final UsernamePasswordAuthenticationInfo upinfo =
            (UsernamePasswordAuthenticationInfo) connectionInfo.getAuthenticationInfo();
        final CredentialsProvider credentialsProvider = new BasicCredentialsProvider();
        credentialsProvider.setCredentials(
            AuthScope.ANY,
            new UsernamePasswordCredentials(upinfo.getUsername(), upinfo.getPassword())
        );
        config.getProperties().put(PROPERTY_CREDENTIALS_PROVIDER, credentialsProvider);
        config.getProperties().put(PROPERTY_PREEMPTIVE_BASIC_AUTHENTICATION, true);
      }
      else {
        throw new IllegalArgumentException(String.format("AuthenticationInfo of type %s is not supported!",
            connectionInfo.getAuthenticationInfo().getClass().getName()));
      }
    }
  }

  protected void applyProxyIfAny(final ConnectionInfo connectionInfo, ApacheHttpClient4Config config) {
    if (connectionInfo.getProxyInfos().size() > 0) {
      final ProxyInfo proxyInfo = connectionInfo.getProxyInfos().get(connectionInfo.getBaseUrl().getProtocol());
      if (proxyInfo != null) {
        config.getProperties().put(
            PROPERTY_PROXY_URI, "http://" + proxyInfo.getProxyHost() + ":" + proxyInfo.getProxyPort()
        );

        if (proxyInfo.getProxyAuthentication() != null) {
          if (proxyInfo.getProxyAuthentication() instanceof UsernamePasswordAuthenticationInfo) {
            final UsernamePasswordAuthenticationInfo upinfo =
                (UsernamePasswordAuthenticationInfo) connectionInfo.getAuthenticationInfo();
            config.getProperties().put(PROPERTY_PROXY_USERNAME, upinfo.getUsername());
            config.getProperties().put(PROPERTY_PROXY_PASSWORD, upinfo.getPassword());
          }
          else {
            throw new IllegalArgumentException(String.format(
                "AuthenticationInfo of type %s is not supported!",
                connectionInfo.getAuthenticationInfo().getClass().getName()));
          }
        }
      }
      else {
        throw new IllegalArgumentException("ProxyInfo and BaseUrl protocols does not align!");
      }
    }
  }
}
TOP

Related Classes of org.sonatype.nexus.client.rest.jersey.NexusClientFactoryImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.