summaryrefslogtreecommitdiff
path: root/eaaf_core_utils/src/main/java/at/gv
diff options
context:
space:
mode:
Diffstat (limited to 'eaaf_core_utils/src/main/java/at/gv')
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslKeySelectionStrategy.java50
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java191
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java (renamed from eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HttpClientFactory.java)344
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java (renamed from eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HttpUtils.java)78
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/IHttpClientFactory.java43
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/IHttpClientFactory.java24
6 files changed, 528 insertions, 202 deletions
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslKeySelectionStrategy.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslKeySelectionStrategy.java
new file mode 100644
index 00000000..1e1e2137
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/EaafSslKeySelectionStrategy.java
@@ -0,0 +1,50 @@
+package at.gv.egiz.eaaf.core.impl.http;
+
+import java.net.Socket;
+import java.util.Map;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.ssl.PrivateKeyDetails;
+import org.apache.http.ssl.PrivateKeyStrategy;
+
+import lombok.extern.slf4j.Slf4j;
+
+/**
+ * Private Key selection implementation for Apache HTTP clients.
+ *
+ * @author tlenz
+ *
+ */
+@Slf4j
+public class EaafSslKeySelectionStrategy implements PrivateKeyStrategy {
+
+ private final String keyAlias;
+
+ /**
+ * Private Key selection implementation for Apache HTTP clients.
+ *
+ * @param alias Alias of the Key that should be used for SSL client authentication.
+ */
+ public EaafSslKeySelectionStrategy(String alias) {
+ this.keyAlias = alias;
+
+ }
+
+ @Override
+ public String chooseAlias(Map<String, PrivateKeyDetails> aliases, Socket socket) {
+ log.trace("Selection SSL client-auth key for alias: {}", keyAlias);
+ final PrivateKeyDetails selected = aliases.get(keyAlias);
+ if (selected != null) {
+ log.trace("Select SL client-auth key with type:", selected.getType());
+ return keyAlias;
+
+ } else {
+ log.warn("KeyStore contains NO key with alias: {}. Using first key from keystore", keyAlias);
+ log.info("Available aliases: {}", StringUtils.join(aliases.keySet(), ", "));
+ return aliases.keySet().iterator().next();
+
+ }
+
+ }
+
+}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java
new file mode 100644
index 00000000..582ad545
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientConfiguration.java
@@ -0,0 +1,191 @@
+package at.gv.egiz.eaaf.core.impl.http;
+
+import java.text.MessageFormat;
+import java.util.UUID;
+
+import javax.annotation.Nonnull;
+
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
+import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration;
+
+import org.apache.commons.lang3.StringUtils;
+
+import lombok.Getter;
+import lombok.Setter;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+@Getter
+public class HttpClientConfiguration {
+
+ private static final String MSG_KEYSTORE_NAME = "KeyStore for httpClient: {0}";
+
+ private static final String ERROR_00 = "internal.httpclient.00";
+ private static final String ERROR_01 = "internal.httpclient.01";
+ private static final String ERROR_02 = "internal.httpclient.02";
+
+ @Nonnull
+ private final String friendlyName;
+
+ @Nonnull
+ private final String uuid;
+
+ @Nonnull
+ private ClientAuthMode authMode = ClientAuthMode.NONE;
+
+ @Setter
+ private String username;
+
+ @Setter
+ private String password;
+
+ @Setter
+ boolean disableHostnameValidation = false;
+
+ @Setter
+ boolean disableTlsHostCertificateValidation = false;
+
+
+ private KeyStoreConfiguration keyStoreConfig;
+
+ @Setter
+ private String sslKeyAlias;
+
+ @Setter
+ private String sslKeyPassword;
+
+ @Setter
+ private boolean followHttpRedirects = true;
+
+ /**
+ * Get a new HTTP-client configuration object.
+ *
+ * @param name FriendlyName of this http client for logging purposes.
+ */
+ public HttpClientConfiguration(String name) {
+ this.friendlyName = name;
+ this.uuid = UUID.randomUUID().toString();
+
+ }
+
+ /**
+ * Set Client authentication-mode from configuration property.
+ *
+ * <p>If the mode is unknown than the {@link ClientAuthMode} is set to <code>NONE</code> </p>
+ *
+ * @param authModeString Modes from {@link ClientAuthMode}
+ */
+ public void setAuthMode(String authModeString) {
+ final ClientAuthMode configAuthMode = HttpClientConfiguration.ClientAuthMode.fromString(authModeString);
+ if (configAuthMode != null) {
+ authMode = configAuthMode;
+
+ } else {
+ log.warn("Can Not parse ClientAuthMode for client: {}! Set mode to default value",
+ friendlyName);
+
+ }
+ }
+
+
+ /**
+ * Validate the internal state of this configuration object.
+ *
+ * @throws EaafConfigurationException In case of a configuration error
+ */
+ public void validate() throws EaafConfigurationException {
+ log.trace("Validating http-client: {}", this.friendlyName);
+ if (this.authMode.equals(ClientAuthMode.PASSWORD)) {
+ if (StringUtils.isEmpty(this.username)) {
+ throw new EaafConfigurationException(ERROR_00, new Object[] {this.friendlyName});
+
+ }
+
+ if (StringUtils.isEmpty(this.password)) {
+ log.warn("Http basic authentication was activated but NOT username was set!");
+
+ }
+
+ } else if (this.authMode.equals(ClientAuthMode.SSL)) {
+ if (this.keyStoreConfig == null) {
+ throw new EaafConfigurationException(ERROR_01, new Object[] {this.friendlyName});
+
+ } else {
+ log.trace("Validating KeyStore: {} for http-client: {} ...",
+ this.keyStoreConfig.getFriendlyName(), this.friendlyName);
+ this.keyStoreConfig.validate();
+
+ }
+
+ if (StringUtils.isEmpty(this.sslKeyPassword)) {
+ throw new EaafConfigurationException(ERROR_02, new Object[] {
+ this.friendlyName, this.keyStoreConfig.getFriendlyName()});
+
+ }
+ }
+
+ }
+
+ /**
+ * Build a {@link KeyStoreConfiguration} object from configuration parameters.
+ *
+ * @param keyStoreType String based KeyStore type
+ * @param keyStorePath Path to KeyStore in case of a software based KeyStore
+ * @param keyStorePassword Password in case of a software based KeyStore
+ * @param keyStoreName Name of the KeyStore in case of a named KeyStore like HSM-Facade
+ * @throws EaafConfigurationException In case of a configuration error
+ */
+ public void buildKeyStoreConfig(String keyStoreType, String keyStorePath,
+ String keyStorePassword, String keyStoreName) throws EaafConfigurationException {
+ final KeyStoreConfiguration config = new KeyStoreConfiguration();
+ config.setKeyStoreType(keyStoreType);
+ config.setFriendlyName(MessageFormat.format(MSG_KEYSTORE_NAME, friendlyName));
+ config.setSoftKeyStoreFilePath(keyStorePath);
+ config.setSoftKeyStorePassword(keyStorePassword);
+ config.setKeyStoreName(keyStoreName);
+ this.keyStoreConfig = config;
+
+ }
+
+ public enum ClientAuthMode {
+ NONE("none"), PASSWORD("password"), SSL("ssl");
+
+ private final String mode;
+
+ ClientAuthMode(final String mode) {
+ this.mode = mode;
+ }
+
+ /**
+ * Get the PVP mode.
+ *
+ * @return
+ */
+ public String getMode() {
+ return this.mode;
+ }
+
+ /**
+ * Get http-client authentication mode from String representation.
+ *
+ * @param s Config parameter
+ * @return
+ */
+ public static ClientAuthMode fromString(final String s) {
+ try {
+ return ClientAuthMode.valueOf(s.toUpperCase());
+
+ } catch (IllegalArgumentException | NullPointerException e) {
+ return null;
+ }
+ }
+
+ @Override
+ public String toString() {
+ return getMode();
+
+ }
+
+ }
+
+}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HttpClientFactory.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java
index e681e705..b6e660da 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HttpClientFactory.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java
@@ -1,11 +1,11 @@
-package at.gv.egiz.eaaf.core.impl.utils;
+package at.gv.egiz.eaaf.core.impl.http;
-import java.security.KeyManagementException;
import java.security.KeyStore;
-import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
-import java.security.UnrecoverableKeyException;
+import java.util.HashMap;
+import java.util.Map;
+import javax.annotation.Nonnull;
import javax.annotation.PostConstruct;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
@@ -13,8 +13,8 @@ import javax.net.ssl.SSLContext;
import at.gv.egiz.eaaf.core.api.idp.IConfiguration;
import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
import at.gv.egiz.eaaf.core.exceptions.EaafException;
+import at.gv.egiz.eaaf.core.exceptions.EaafFactoryException;
import at.gv.egiz.eaaf.core.impl.credential.EaafKeyStoreFactory;
-import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration;
import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType;
import org.apache.commons.lang3.StringUtils;
@@ -41,22 +41,19 @@ import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.protocol.HttpContext;
-import org.apache.http.ssl.SSLContexts;
import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.core.io.ResourceLoader;
import lombok.extern.slf4j.Slf4j;
@Slf4j
public class HttpClientFactory implements IHttpClientFactory {
- @Autowired(required = true)
+ @Autowired
private IConfiguration basicConfig;
+ @Autowired
+ private EaafKeyStoreFactory keyStoreFactory;
- @Autowired(required = true)
- ResourceLoader resourceLoader;
-
- @Autowired private EaafKeyStoreFactory keyStoreFactory;
+ private static final String ERROR_03 = "internal.httpclient.03";
public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_USE =
"client.http.connection.pool.use";
@@ -84,9 +81,10 @@ public class HttpClientFactory implements IHttpClientFactory {
"client.auth.ssl.keystore.name";
public static final String PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_TYPE =
"client.auth.ssl.keystore.type";
+ public static final String PROP_CONFIG_CLIENT_AUTH_SSL_KEY_ALIAS =
+ "client.auth.ssl.key.alias";
public static final String PROP_CONFIG_CLIENT_AUTH_SSL_KEY_PASSWORD =
"client.auth.ssl.key.password";
- public static final String PROP_CONFIG_CLIENT_AUTH_SSL_KEY_ALIAS = "client.auth.ssl.key.alias";
// default configuration values
public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET = "15";
@@ -95,48 +93,8 @@ public class HttpClientFactory implements IHttpClientFactory {
public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL = "500";
public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE = "100";
- public enum ClientAuthMode {
- NONE("none"), PASSWORD("password"), SSL("ssl");
-
- private final String mode;
-
- ClientAuthMode(final String mode) {
- this.mode = mode;
- }
-
- /**
- * Get the PVP mode.
- *
- * @return
- */
- public String getMode() {
- return this.mode;
- }
-
- /**
- * Get http-client authentication mode from String representation.
- *
- * @param s Config parameter
- * @return
- */
- public static ClientAuthMode fromString(final String s) {
- try {
- return ClientAuthMode.valueOf(s.toUpperCase());
-
- } catch (IllegalArgumentException | NullPointerException e) {
- return null;
- }
- }
-
- @Override
- public String toString() {
- return getMode();
-
- }
-
- }
-
- private HttpClientBuilder httpClientBuilder = null;
+ private String defaultConfigurationId = null;
+ private final Map<String, HttpClientBuilder> availableBuilders = new HashMap<>();
/*
* (non-Javadoc)
@@ -151,151 +109,145 @@ public class HttpClientFactory implements IHttpClientFactory {
@Override
public CloseableHttpClient getHttpClient(final boolean followRedirects) {
- RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
- if (!followRedirects) {
- redirectStrategy = new RedirectStrategy() {
+ return availableBuilders.get(defaultConfigurationId).setRedirectStrategy(
+ buildRedirectStrategy(followRedirects)).build();
- @Override
- public boolean isRedirected(final HttpRequest request, final HttpResponse response,
- final HttpContext context) throws ProtocolException {
- return false;
- }
+ }
- @Override
- public HttpUriRequest getRedirect(final HttpRequest request, final HttpResponse response,
- final HttpContext context) throws ProtocolException {
- return null;
- }
- };
- }
+ @Override
+ public CloseableHttpClient getHttpClient(@Nonnull HttpClientConfiguration config) throws EaafException {
+ log.trace("Build http client for: {}", config.getFriendlyName());
+ HttpClientBuilder builder = null;
+ if (availableBuilders.containsKey(config.getUuid())) {
+ builder = availableBuilders.get(config.getUuid());
- return httpClientBuilder.setRedirectStrategy(redirectStrategy).build();
+ } else {
+ log.debug("Initialize new http-client builder for: {}", config.getFriendlyName());
- }
+ //validate configuration object
+ config.validate();
- @PostConstruct
- private void initalize() {
- // initialize http client
- log.trace("Initializing HTTP Client-builder ... ");
- httpClientBuilder = HttpClients.custom();
+ builder = HttpClients.custom();
+ builder.setDefaultRequestConfig(buildDefaultRequestConfig());
- // set default request configuration
- final RequestConfig requestConfig =
- RequestConfig.custom()
- .setConnectTimeout(
- Integer.parseInt(basicConfig.getBasicConfiguration(
- PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_CONNECTION,
- DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_CONNECTION)) * 1000)
- .setConnectionRequestTimeout(Integer.parseInt(basicConfig.getBasicConfiguration(
- PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST,
- DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST)) * 1000)
- .setSocketTimeout(Integer.parseInt(
- basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET,
- DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET))
- * 1000)
- .build();
- httpClientBuilder.setDefaultRequestConfig(requestConfig);
+ //inject basic authentication infos
+ injectBasicAuthenticationIfRequired(builder, config);
- ClientAuthMode clientAuthMode = ClientAuthMode.fromString(
- basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_MODE, ClientAuthMode.NONE.getMode()));
- if (clientAuthMode == null) {
- log.warn("Can Not parse ClientAuthMode! Set mode to default value");
- clientAuthMode = ClientAuthMode.NONE;
+ //inject authentication if required
+ final LayeredConnectionSocketFactory sslConnectionFactory = getSslContext(config);
- }
+ // set pool connection if required
+ injectDefaultConnectionPoolIfRequired(builder, sslConnectionFactory);
- // inject basic http authentication if required
- log.info("Client authentication-mode is set to: {}", clientAuthMode);
- injectBasicAuthenticationIfRequired(clientAuthMode);
+ availableBuilders.put(config.getUuid(), builder);
- // inject authentication if required
- final LayeredConnectionSocketFactory sslConnectionFactory = getSslContext(clientAuthMode);
+ }
- // set pool connection if required
- injectConnectionPoolIfRequired(sslConnectionFactory);
+ return builder.setRedirectStrategy(
+ buildRedirectStrategy(config.isFollowHttpRedirects())).build();
}
- private void injectBasicAuthenticationIfRequired(final ClientAuthMode clientAuthMode) {
- if (clientAuthMode.equals(ClientAuthMode.PASSWORD)) {
- final CredentialsProvider provider = new BasicCredentialsProvider();
+ @PostConstruct
+ private void initalize() throws EaafException {
+ final HttpClientConfiguration defaultHttpClientConfig = buildDefaultHttpClientConfiguration();
- final String username =
- basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_AUTH_HTTP_USERNAME);
- final String password =
- basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_AUTH_HTTP_PASSORD);
+ // initialize http client
+ log.trace("Initializing default HTTP-Client builder ... ");
+ final HttpClientBuilder defaultHttpClientBuilder = HttpClients.custom();
- if (StringUtils.isEmpty(username)) {
- log.warn("Http basic authentication was activated but NOT username was set!");
+ // set default request configuration
+ defaultHttpClientBuilder.setDefaultRequestConfig(buildDefaultRequestConfig());
- }
+ //inject http basic authentication
+ injectBasicAuthenticationIfRequired(defaultHttpClientBuilder, defaultHttpClientConfig);
- log.trace("Injecting basic authentication with username: {} and password: {}", username,
- password);
- final UsernamePasswordCredentials credentials =
- new UsernamePasswordCredentials(username, password);
- provider.setCredentials(AuthScope.ANY, credentials);
- httpClientBuilder.setDefaultCredentialsProvider(provider);
- log.info("Basic http authentication was injected with username: {}", username);
+ // inject authentication if required
+ final LayeredConnectionSocketFactory sslConnectionFactory =
+ getSslContext(defaultHttpClientConfig);
- } else {
- log.trace("Injection of Http Basic authentication was skipped");
+ // set pool connection if required
+ injectDefaultConnectionPoolIfRequired(defaultHttpClientBuilder, sslConnectionFactory);
- }
+ //set default http client builder
+ defaultConfigurationId = defaultHttpClientConfig.getUuid();
+ availableBuilders.put(defaultConfigurationId, defaultHttpClientBuilder);
}
- private SSLContext buildSslContextWithSslClientAuthentication()
- throws KeyManagementException, UnrecoverableKeyException, NoSuchAlgorithmException,
- KeyStoreException, EaafConfigurationException {
- log.trace("Injecting SSL client-authentication into http client ... ");
- final KeyStore keystore = getSslAuthKeyStore();
- final String keyPasswordString =
- basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_AUTH_SSL_KEY_PASSWORD);
- log.trace("Open SSL Client-Auth keystore with password: {}", keyPasswordString);
- final char[] keyPassword = keyPasswordString == null ? StringUtils.EMPTY.toCharArray()
- : keyPasswordString.toCharArray();
- return SSLContexts.custom().loadKeyMaterial(keystore, keyPassword).build();
+ private HttpClientConfiguration buildDefaultHttpClientConfiguration() throws EaafConfigurationException {
+ final HttpClientConfiguration config = new HttpClientConfiguration("Default");
+ // inject basic http authentication if required
+ config.setAuthMode(basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_MODE,
+ HttpClientConfiguration.ClientAuthMode.NONE.getMode()));
+ log.info("Default client authentication-mode is set to: {}", config.getAuthMode());
+
+ // set Username and Password if available
+ config.setUsername(basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_AUTH_HTTP_USERNAME));
+ config.setPassword(basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_AUTH_HTTP_PASSORD));
+
+ // set SSL Client auth. informations if available
+ config.buildKeyStoreConfig(
+ basicConfig.getBasicConfiguration(
+ PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_TYPE, KeyStoreType.PKCS12.getKeyStoreType()),
+ basicConfig.getBasicConfiguration(
+ PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_PATH, StringUtils.EMPTY),
+ basicConfig.getBasicConfiguration(
+ PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_PASSORD, StringUtils.EMPTY),
+ basicConfig.getBasicConfiguration(
+ PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_NAME, StringUtils.EMPTY));
+
+ config.setSslKeyAlias(
+ basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_AUTH_SSL_KEY_ALIAS));
+ config.setSslKeyPassword(
+ basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_AUTH_SSL_KEY_PASSWORD));
+
+ config.setDisableHostnameValidation(basicConfig.getBasicConfigurationBoolean(
+ PROP_CONFIG_CLIENT_HTTP_SSL_HOSTNAMEVERIFIER_TRUSTALL, false));
+
+ // validate configuration object
+ config.validate();
+
+ return config;
}
- private KeyStore getSslAuthKeyStore() throws EaafConfigurationException {
- final String keyStoreType = basicConfig.getBasicConfiguration(
- PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_TYPE, KeyStoreType.PKCS12.getKeyStoreType());
- final String localKeyStorePath = basicConfig
- .getBasicConfiguration(PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_PATH, StringUtils.EMPTY);
- final String keyStorePassword = basicConfig
- .getBasicConfiguration(PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_PASSORD, StringUtils.EMPTY);
- final String keyStoreName = basicConfig
- .getBasicConfiguration(PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_NAME, StringUtils.EMPTY);
-
- try {
- final KeyStoreConfiguration keyStoreConfig = new KeyStoreConfiguration();
- keyStoreConfig.setKeyStoreType(keyStoreType);
- keyStoreConfig.setFriendlyName("HttpClient Keystore");
- keyStoreConfig.setSoftKeyStoreFilePath(localKeyStorePath);
- keyStoreConfig.setSoftKeyStorePassword(keyStorePassword);
- keyStoreConfig.setKeyStoreName(keyStoreName);
-
- log.debug("Open keyStore with type: {}", keyStoreType);
- final KeyStore keyStore = keyStoreFactory.buildNewKeyStore(keyStoreConfig).getFirst();
+ private void injectBasicAuthenticationIfRequired(HttpClientBuilder builder,
+ final HttpClientConfiguration httpClientConfig) {
+ if (httpClientConfig.getAuthMode().equals(HttpClientConfiguration.ClientAuthMode.PASSWORD)) {
+ final CredentialsProvider provider = new BasicCredentialsProvider();
+ log.trace("Injecting basic authentication with username: {} and password: {}",
+ httpClientConfig.getUsername(), httpClientConfig.getPassword());
+ final UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(
+ httpClientConfig.getUsername(), httpClientConfig.getPassword());
- return keyStore;
+ final AuthScope scope = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT, AuthScope.ANY_REALM);
+ provider.setCredentials(scope, credentials);
+ builder.setDefaultCredentialsProvider(provider);
+ log.info("Basic http authentication was injected with username: {}",
+ httpClientConfig.getUsername());
- } catch (final EaafException e) {
- log.warn("Can NOT read keyStore: {} from filesystem", localKeyStorePath, null, e);
- throw new EaafConfigurationException("Can NOT read keyStore: {} from filesystem",
- new Object[] { localKeyStorePath }, e);
+ } else {
+ log.trace("Injection of Http Basic authentication was skipped");
}
}
- private LayeredConnectionSocketFactory getSslContext(final ClientAuthMode clientAuthMode) {
+ @Nonnull
+ private LayeredConnectionSocketFactory getSslContext(final HttpClientConfiguration httpClientConfig)
+ throws EaafException {
SSLContext sslContext = null;
try {
- if (clientAuthMode.equals(ClientAuthMode.SSL)) {
- sslContext = buildSslContextWithSslClientAuthentication();
+ if (httpClientConfig.getAuthMode().equals(HttpClientConfiguration.ClientAuthMode.SSL)) {
+ log.debug("Open keyStore with type: {}", httpClientConfig.getKeyStoreConfig().getKeyStoreType());
+ final KeyStore keyStore = keyStoreFactory.buildNewKeyStore(httpClientConfig.getKeyStoreConfig())
+ .getFirst();
+
+ log.trace("Injecting SSL client-authentication into http client ... ");
+ sslContext = HttpUtils.buildSslContextWithSslClientAuthentication(keyStore,
+ httpClientConfig.getSslKeyAlias(), httpClientConfig.getSslKeyPassword(),
+ httpClientConfig.isDisableTlsHostCertificateValidation(), httpClientConfig.getFriendlyName());
} else {
log.trace("Initializing default SSL Context ... ");
@@ -305,8 +257,7 @@ public class HttpClientFactory implements IHttpClientFactory {
// set hostname verifier
HostnameVerifier hostnameVerifier = null;
- if (basicConfig.getBasicConfigurationBoolean(
- PROP_CONFIG_CLIENT_HTTP_SSL_HOSTNAMEVERIFIER_TRUSTALL, false)) {
+ if (httpClientConfig.isDisableHostnameValidation()) {
hostnameVerifier = new NoopHostnameVerifier();
log.warn("HTTP client-builder deactivates SSL Host-name verification!");
@@ -314,22 +265,20 @@ public class HttpClientFactory implements IHttpClientFactory {
final LayeredConnectionSocketFactory sslSocketFactory =
new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
-
+ log.debug("HTTP client-builder successfuly initialized");
return sslSocketFactory;
- } catch (final NoSuchAlgorithmException | KeyManagementException | UnrecoverableKeyException
- | KeyStoreException | EaafConfigurationException e) {
+ } catch (final NoSuchAlgorithmException e) {
log.warn("HTTP client-builder can NOT initialze SSL-Context", e);
+ throw new EaafFactoryException(ERROR_03, new Object[] {
+ httpClientConfig.getFriendlyName(), e.getMessage()}, e);
}
- log.info("HTTP client-builder successfuly initialized");
- return null;
-
}
- private void injectConnectionPoolIfRequired(
- final LayeredConnectionSocketFactory sslConnectionFactory) {
+ private void injectDefaultConnectionPoolIfRequired(
+ HttpClientBuilder builder, final LayeredConnectionSocketFactory sslConnectionFactory) {
if (basicConfig.getBasicConfigurationBoolean(PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_USE,
true)) {
PoolingHttpClientConnectionManager pool;
@@ -355,15 +304,56 @@ public class HttpClientFactory implements IHttpClientFactory {
basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL,
DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL)));
- httpClientBuilder.setConnectionManager(pool);
+ builder.setConnectionManager(pool);
log.debug("Initalize http-client pool with, maxTotal: {} maxPerRoute: {}", pool.getMaxTotal(),
pool.getDefaultMaxPerRoute());
} else if (sslConnectionFactory != null) {
log.trace("Inject SSLSocketFactory without connection pool");
- httpClientBuilder.setSSLSocketFactory(sslConnectionFactory);
+ builder.setSSLSocketFactory(sslConnectionFactory);
+
+ }
+
+ }
+
+ private RequestConfig buildDefaultRequestConfig() {
+ final RequestConfig requestConfig =
+ RequestConfig.custom()
+ .setConnectTimeout(
+ Integer.parseInt(basicConfig.getBasicConfiguration(
+ PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_CONNECTION,
+ DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_CONNECTION)) * 1000)
+ .setConnectionRequestTimeout(Integer.parseInt(basicConfig.getBasicConfiguration(
+ PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST,
+ DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST)) * 1000)
+ .setSocketTimeout(Integer.parseInt(
+ basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET,
+ DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET))
+ * 1000)
+ .build();
+ return requestConfig;
+
+ }
+
+ private static RedirectStrategy buildRedirectStrategy(final boolean followRedirects) {
+ RedirectStrategy redirectStrategy = new DefaultRedirectStrategy();
+ if (!followRedirects) {
+ redirectStrategy = new RedirectStrategy() {
+
+ @Override
+ public boolean isRedirected(final HttpRequest request, final HttpResponse response,
+ final HttpContext context) throws ProtocolException {
+ return false;
+ }
+ @Override
+ public HttpUriRequest getRedirect(final HttpRequest request, final HttpResponse response,
+ final HttpContext context) throws ProtocolException {
+ return null;
+ }
+ };
}
+ return redirectStrategy;
}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HttpUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java
index 66356ba0..2d514912 100644
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/HttpUtils.java
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java
@@ -16,14 +16,35 @@
* works that you distribute must include a readable copy of the "NOTICE" text file.
*/
-package at.gv.egiz.eaaf.core.impl.utils;
+package at.gv.egiz.eaaf.core.impl.http;
+import java.security.KeyManagementException;
+import java.security.KeyStore;
+import java.security.KeyStoreException;
+import java.security.NoSuchAlgorithmException;
+import java.security.UnrecoverableKeyException;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.net.ssl.SSLContext;
import javax.servlet.http.HttpServletRequest;
+import at.gv.egiz.eaaf.core.exceptions.EaafConfigurationException;
+import at.gv.egiz.eaaf.core.exceptions.EaafFactoryException;
+
import org.apache.commons.lang3.StringUtils;
+import org.apache.http.conn.ssl.TrustAllStrategy;
+import org.apache.http.ssl.SSLContextBuilder;
+import org.apache.http.ssl.SSLContexts;
+import org.apache.http.ssl.TrustStrategy;
+
+import lombok.extern.slf4j.Slf4j;
+@Slf4j
public class HttpUtils {
+ private static final String ERROR_03 = "internal.httpclient.03";
+
/**
* Helper method to retrieve server URL including context path.
*
@@ -115,4 +136,59 @@ public class HttpUtils {
}
}
+ /**
+ * Initialize a {@link SSLContext} with a {@link KeyStore} that uses X509 Client
+ * authentication.
+ *
+ * @param keyStore KeyStore with private keys that should be
+ * used
+ * @param keyAlias Alias of the key that should be used. If
+ * the alias is null, than the first key that
+ * is found will be selected.
+ * @param keyPasswordString Password of the Key in this keystore
+ * @param trustAllServerCertificates Deactivate SSL server-certificate
+ * validation
+ * @param friendlyName FriendlyName of the http client for logging
+ * purposes
+ * @return {@link SSLContext} with X509 client authentication
+ * @throws EaafConfigurationException In case of a configuration error
+ * @throws EaafFactoryException In case of a {@link SSLContext}
+ * initialization error
+ */
+ public static SSLContext buildSslContextWithSslClientAuthentication(@Nonnull final KeyStore keyStore,
+ @Nullable String keyAlias, @Nullable String keyPasswordString,
+ boolean trustAllServerCertificates, @Nonnull String friendlyName)
+ throws EaafConfigurationException, EaafFactoryException {
+ try {
+ log.trace("Open SSL Client-Auth keystore with password: {}", keyPasswordString);
+ final char[] keyPassword = keyPasswordString == null ? StringUtils.EMPTY.toCharArray()
+ : keyPasswordString.toCharArray();
+
+ SSLContextBuilder sslContextBuilder = SSLContexts.custom();
+ if (StringUtils.isNotEmpty(keyAlias)) {
+ sslContextBuilder = sslContextBuilder
+ .loadKeyMaterial(keyStore, keyPassword, new EaafSslKeySelectionStrategy(keyAlias));
+
+ } else {
+ sslContextBuilder = sslContextBuilder
+ .loadKeyMaterial(keyStore, keyPassword);
+
+ }
+
+ if (trustAllServerCertificates) {
+ log.warn("Http-client:{} trusts ALL TLS server-certificates!");
+ final TrustStrategy trustStrategy = new TrustAllStrategy();
+ sslContextBuilder = sslContextBuilder.loadTrustMaterial(trustStrategy);
+
+ }
+
+ return sslContextBuilder.build();
+
+ } catch (NoSuchAlgorithmException | KeyManagementException | UnrecoverableKeyException
+ | KeyStoreException e) {
+ throw new EaafFactoryException(ERROR_03, new Object[] { friendlyName, e.getMessage() }, e);
+
+ }
+ }
+
}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/IHttpClientFactory.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/IHttpClientFactory.java
new file mode 100644
index 00000000..7ec58d46
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/IHttpClientFactory.java
@@ -0,0 +1,43 @@
+package at.gv.egiz.eaaf.core.impl.http;
+
+import javax.annotation.Nonnull;
+
+import at.gv.egiz.eaaf.core.exceptions.EaafException;
+
+import org.apache.http.impl.client.CloseableHttpClient;
+
+public interface IHttpClientFactory {
+
+ /**
+ * Return an instance of a Apache HTTP client that uses
+ * default configuration properties from {@link IHttpClientFactory} implementation
+ * and follows http redirects automatically.
+ *
+ * @return http client
+ */
+ @Nonnull
+ CloseableHttpClient getHttpClient();
+
+ /**
+ * Return an instance of a Apache HTTP client that uses
+ * default configuration properties from {@link IHttpClientFactory} implementation.
+ *
+ * @param followRedirects if <code>false</code>, the client does not flow 30x
+ * http redirects
+ * @return http client
+ */
+ @Nonnull
+ CloseableHttpClient getHttpClient(boolean followRedirects);
+
+ /**
+ * Return an instance of a Apache HTTP client based in {@link HttpClientConfiguration}.
+ *
+ * @param config Configuration object for this http client
+ * @return http client
+ * @throws EaafException In case of a http-client initialization problem
+ */
+ @Nonnull
+ CloseableHttpClient getHttpClient(@Nonnull HttpClientConfiguration config)
+ throws EaafException;
+
+}
diff --git a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/IHttpClientFactory.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/IHttpClientFactory.java
deleted file mode 100644
index f922e1ac..00000000
--- a/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/utils/IHttpClientFactory.java
+++ /dev/null
@@ -1,24 +0,0 @@
-package at.gv.egiz.eaaf.core.impl.utils;
-
-import org.apache.http.impl.client.CloseableHttpClient;
-
-public interface IHttpClientFactory {
-
- /**
- * Return an instance of a Apache HTTP client that follows http redirects
- * automatically.
- *
- * @return
- */
- CloseableHttpClient getHttpClient();
-
- /**
- * Return an instance of a Apache HTTP client.
- *
- * @param followRedirects if <code>false</code>, the client does not flow 30x
- * http redirects
- * @return
- */
- CloseableHttpClient getHttpClient(boolean followRedirects);
-
-}