/* * Copyright (C) 2014 Intel Corporation * All rights reserved. */ package com.intel.mtwilson.jaxrs2.client; import com.intel.dcsg.cpg.tls.policy.TlsConnection; import java.net.URL; import org.glassfish.jersey.client.ClientConfig; import com.intel.mtwilson.security.http.jaxrs.HmacAuthorizationFilter; import com.intel.mtwilson.security.http.jaxrs.X509AuthorizationFilter; //import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; //jersey 2.10.1 import org.glassfish.jersey.client.filter.HttpBasicAuthFilter; //jersey 2.4.1 import com.intel.dcsg.cpg.crypto.RsaCredentialX509; import com.intel.dcsg.cpg.crypto.SimpleKeystore; import com.intel.dcsg.cpg.io.FileResource; import java.io.File; import java.util.Properties; import com.intel.dcsg.cpg.configuration.Configuration; import com.intel.dcsg.cpg.configuration.PropertiesConfiguration; import com.intel.dcsg.cpg.crypto.CryptographyException; import com.intel.dcsg.cpg.tls.policy.TlsPolicy; import com.intel.dcsg.cpg.tls.policy.TlsPolicyManager; import com.intel.dcsg.cpg.tls.policy.TlsUtil; import java.util.logging.Logger; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.client.WebTarget; import org.glassfish.jersey.filter.LoggingFilter; import com.intel.mtwilson.jaxrs2.feature.JacksonFeature; import java.io.FileNotFoundException; import java.net.MalformedURLException; import java.security.KeyManagementException; import java.security.KeyStoreException; import java.security.NoSuchAlgorithmException; import java.security.UnrecoverableEntryException; import java.security.cert.CertificateEncodingException; //import org.glassfish.jersey.client.HttpUrlConnectorProvider; // jersey 2.10.1 import org.glassfish.jersey.client.HttpUrlConnector; // jersey 2.4.1 /** * Examples: * * <pre> * JaxrsClient client = JaxrsClientBuilder.factory().url(url).build(); * JaxrsClient client = JaxrsClientBuilder.factory().configuration(properties).build(); * JaxrsClient client = JaxrsClientBuilder.factory().configuration(configuration).build(); * JaxrsClient client = JaxrsClientBuilder.factory().tlsConnection(tlsConnection).build(); * JaxrsClient client = JaxrsClientBuilder.factory().url(url).tlsPolicy(tlsPolicy).build(); * </pre> * * @author jbuhacoff */ public class JaxrsClientBuilder { private static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(JaxrsClientBuilder.class); public static JaxrsClientBuilder factory() { return new JaxrsClientBuilder(); } private ClientConfig clientConfig; private Configuration configuration; private TlsPolicy tlsPolicy; private URL url; private TlsConnection tlsConnection; public JaxrsClientBuilder() { clientConfig = new ClientConfig(); clientConfig.register(JacksonFeature.class); clientConfig.register(com.intel.mtwilson.jaxrs2.provider.JacksonXmlMapperProvider.class); clientConfig.register(com.intel.mtwilson.jaxrs2.provider.JacksonObjectMapperProvider.class); // clientConfig.register(com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider.class); clientConfig.register(com.intel.mtwilson.jaxrs2.provider.X509CertificateArrayPemProvider.class); clientConfig.register(com.intel.mtwilson.jaxrs2.provider.X509CertificateDerProvider.class); clientConfig.register(com.intel.mtwilson.jaxrs2.provider.X509CertificatePemProvider.class); clientConfig.register(com.intel.mtwilson.jaxrs2.provider.DateParamConverterProvider.class); } /** * Configures a client using authentication settings in the properties * argument. The API URL must be set as mtwilson.api.url or * mtwilson.api.baseurl in the properties. * * To use BASIC password authentication, set mtwilson.api.username and * mtwilson.api.password. * * To use HMAC (MtWilson-specific) authentication, set mtwilson.api.clientId * and mtwilson.api.secretKey * * To use X509 (MtWilson-specific) authentication, set: * mtwilson.api.keystore = path to client-keystore.jks * mtwilson.api.keystore.password = password protecting client-keystore.jks * mtwilson.api.key.alias = alias of private key in the keystore; usually * same as username or name of keystore like "client-keystore" * mtwilson.api.key.password = password protecting the key, usually same as * the keystore password * * @param properties * @return */ public JaxrsClientBuilder configuration(Properties properties) { configuration = new PropertiesConfiguration(properties); return this; } public JaxrsClientBuilder configuration(Configuration configuration) { this.configuration = configuration; return this; } private void authentication() throws KeyManagementException, FileNotFoundException, KeyStoreException, NoSuchAlgorithmException, UnrecoverableEntryException, CertificateEncodingException, CryptographyException { if (configuration == null) { return; } // X509 authorization SimpleKeystore keystore = null; if (configuration.getString("mtwilson.api.keystore") != null && configuration.getString("mtwilson.api.keystore.password") != null) { FileResource resource = new FileResource(new File(configuration.getString("mtwilson.api.keystore"))); keystore = new SimpleKeystore(resource, configuration.getString("mtwilson.api.keystore.password")); } if (keystore != null && configuration.getString("mtwilson.api.key.alias") != null && configuration.getString("mtwilson.api.key.password") != null) { log.debug("Registering X509 credentials for {}", configuration.getString("mtwilson.api.key.alias")); log.debug("Loading key {} from keystore {}", configuration.getString("mtwilson.api.key.alias"), configuration.getString("mtwilson.api.keystore")); RsaCredentialX509 credential = keystore.getRsaCredentialX509(configuration.getString("mtwilson.api.key.alias"), configuration.getString("mtwilson.api.key.password")); log.debug(credential.getPublicKey().toString()); clientConfig.register(new X509AuthorizationFilter(credential)); } // HMAC authorization if (configuration.getString("mtwilson.api.clientId") != null && configuration.getString("mtwilson.api.secretKey") != null) { log.debug("Registering HMAC credentials for {}", configuration.getString("mtwilson.api.clientId")); clientConfig.register(new HmacAuthorizationFilter(configuration.getString("mtwilson.api.clientId"), configuration.getString("mtwilson.api.secretKey"))); } // BASIC authorization will only be registered if configuration is present but also the feature itself will only add an Authorization header if there isn't already one present if (configuration.getString("mtwilson.api.username") != null && configuration.getString("mtwilson.api.password") != null) { log.debug("Registering BASIC credentials for {}", configuration.getString("mtwilson.api.username")); // clientConfig.register( new BasicPasswordAuthorizationFilter(configuration.getString("mtwilson.api.username"), configuration.getString("mtwilson.api.password"))); // HttpAuthenticationFeature feature = HttpAuthenticationFeature.basic(configuration.getString("mtwilson.api.username"), configuration.getString("mtwilson.api.password")); // clientConfig.register(feature); clientConfig.register(new HttpBasicAuthFilter(configuration.getString("mtwilson.api.username"), configuration.getString("mtwilson.api.password"))); // jersey 2.4.1 // clientConfig.register(HttpAuthenticationFeature.basic(configuration.getString("mtwilson.api.username"), configuration.getString("mtwilson.api.password"))); // jersey 2.10.1 } } private void url() throws MalformedURLException { if (url == null) { if (configuration != null) { url = new URL(configuration.getString("mtwilson.api.url", configuration.getString("mtwilson.api.baseurl"))); // example: "http://localhost:8080/v2"; } } } private void tls() { assert url != null; if (tlsConnection == null) { if (tlsPolicy != null) { log.debug("creating TlsConnection from URL and TlsPolicy"); tlsConnection = new TlsConnection(url, tlsPolicy); } else if (configuration != null) { tlsPolicy = PropertiesTlsPolicyFactory.createTlsPolicy(configuration); log.debug("TlsPolicy is {}", this.tlsPolicy.getClass().getName()); tlsConnection = new TlsConnection(url, tlsPolicy); log.debug("set TlsConnection from configuration"); } } if (tlsConnection != null) { // log.debug("setting HttpUrlConnector with TlsPolicyAwareConnectionFactory"); clientConfig.connector(new HttpUrlConnector(new TlsPolicyAwareConnectionFactory(tlsConnection.getTlsPolicy()))); // jersey 2.4.1 // clientConfig.connectorProvider(new HttpUrlConnectorProvider().connectionFactory(new TlsPolicyAwareConnectionFactory(tlsConnection))); // log.debug("setting HttpsURLConnection defaults"); // TlsUtil.setHttpsURLConnectionDefaults(tlsConnection); } } // you can set this instead of url and tlsPolicy public JaxrsClientBuilder tlsConnection(TlsConnection tlsConnection) { log.debug("set TlsConnection"); this.tlsConnection = tlsConnection; this.url = tlsConnection.getURL(); this.tlsPolicy = tlsConnection.getTlsPolicy(); log.debug("TlsPolicy is {}", this.tlsPolicy.getClass().getName()); return this; } public JaxrsClientBuilder url(URL url) { this.url = url; return this; } public JaxrsClientBuilder tlsPolicy(TlsPolicy tlsPolicy) { this.tlsPolicy = tlsPolicy; return this; } public JaxrsClient build() { try { url(); tls(); // sets tls connection authentication(); // adds to clientConfig // client = ClientBuilder.newClient(clientConfig); // Client client = ClientBuilder.newBuilder().sslContext(tlsConnection.getSSLContext()).hostnameVerifier(tlsConnection.getTlsPolicy().getHostnameVerifier()).withConfig(clientConfig).build(); Client client = ClientBuilder.newBuilder() .withConfig(clientConfig) .sslContext(tlsConnection.getSSLContext()) // when commented out, get pkix path building failure from java's built-in ssl context... when enabled, our custom ssl context doesn't get called at all. // .hostnameVerifier(TlsPolicyManager.getInstance().getHostnameVerifier()) .hostnameVerifier(tlsConnection.getTlsPolicy().getHostnameVerifier()) .build(); if (configuration != null && configuration.getBoolean("org.glassfish.jersey.filter.LoggingFilter.printEntity", true)) { client.register(new LoggingFilter(Logger.getLogger("org.glassfish.jersey.filter.LoggingFilter"), true)); } else { client.register(new LoggingFilter()); } // client.register(com.intel.mtwilson.jaxrs2.provider.JacksonXmlMapperProvider.class); // client.register(com.intel.mtwilson.jaxrs2.provider.JacksonObjectMapperProvider.class); WebTarget target = client.target(url.toExternalForm()); return new JaxrsClient(client, target); } catch (MalformedURLException | KeyManagementException | FileNotFoundException | KeyStoreException | NoSuchAlgorithmException | UnrecoverableEntryException | CertificateEncodingException | CryptographyException e) { throw new IllegalArgumentException("Cannot construct client", e); } } /* register(com.intel.mtwilson.jaxrs2.provider.JacksonXmlMapperProvider.class); register(com.intel.mtwilson.jaxrs2.provider.JacksonObjectMapperProvider.class); // added register(com.intel.mtwilson.jaxrs2.provider.JacksonYamlObjectMapperProvider.class); register(com.intel.mtwilson.jaxrs2.provider.ApplicationYamlProvider.class); register(com.intel.mtwilson.jaxrs2.provider.X509CertificatePemProvider.class); register(com.intel.mtwilson.jaxrs2.provider.X509CertificateDerProvider.class); register(com.intel.mtwilson.jaxrs2.provider.X509CertificateArrayPemProvider.class); register(com.fasterxml.jackson.jaxrs.base.JsonMappingExceptionMapper.class); register(com.fasterxml.jackson.jaxrs.base.JsonParseExceptionMapper.class); register(com.fasterxml.jackson.jaxrs.json.JacksonJsonProvider.class); // added //register(com.fasterxml.jackson.jaxrs.json.JsonParseExceptionMapper.class); register(com.fasterxml.jackson.jaxrs.json.JacksonJaxbJsonProvider.class); //register(com.fasterxml.jackson.jaxrs.json.JsonMappingExceptionMapper.class); register(com.fasterxml.jackson.jaxrs.xml.JacksonJaxbXMLProvider.class); //register(com.fasterxml.jackson.jaxrs.xml.JsonParseExceptionMapper.class); register(com.fasterxml.jackson.jaxrs.xml.JacksonXMLProvider.class); //register(com.fasterxml.jackson.jaxrs.xml.JsonMappingExceptionMapper.class); * */ }