summaryrefslogtreecommitdiff
path: root/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http
diff options
context:
space:
mode:
Diffstat (limited to 'eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http')
-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.java354
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java194
-rw-r--r--eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/IHttpClientFactory.java43
5 files changed, 832 insertions, 0 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/http/HttpClientFactory.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java
new file mode 100644
index 00000000..00d5891a
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpClientFactory.java
@@ -0,0 +1,354 @@
+package at.gv.egiz.eaaf.core.impl.http;
+
+import java.security.KeyStore;
+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;
+
+import org.apache.commons.lang3.StringUtils;
+import org.apache.http.HttpRequest;
+import org.apache.http.HttpResponse;
+import org.apache.http.ProtocolException;
+import org.apache.http.auth.AuthScope;
+import org.apache.http.auth.UsernamePasswordCredentials;
+import org.apache.http.client.CredentialsProvider;
+import org.apache.http.client.RedirectStrategy;
+import org.apache.http.client.config.RequestConfig;
+import org.apache.http.client.methods.HttpUriRequest;
+import org.apache.http.config.Registry;
+import org.apache.http.config.RegistryBuilder;
+import org.apache.http.config.SocketConfig;
+import org.apache.http.conn.socket.ConnectionSocketFactory;
+import org.apache.http.conn.socket.LayeredConnectionSocketFactory;
+import org.apache.http.conn.socket.PlainConnectionSocketFactory;
+import org.apache.http.conn.ssl.NoopHostnameVerifier;
+import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
+import org.apache.http.impl.client.BasicCredentialsProvider;
+import org.apache.http.impl.client.CloseableHttpClient;
+import org.apache.http.impl.client.DefaultRedirectStrategy;
+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 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.impl.credential.EaafKeyStoreFactory;
+import at.gv.egiz.eaaf.core.impl.credential.KeyStoreConfiguration.KeyStoreType;
+import lombok.extern.slf4j.Slf4j;
+
+@Slf4j
+public class HttpClientFactory implements IHttpClientFactory {
+
+ @Autowired
+ private IConfiguration basicConfig;
+ @Autowired
+ private EaafKeyStoreFactory keyStoreFactory;
+
+ public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_USE =
+ "client.http.connection.pool.use";
+ public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL =
+ "client.http.connection.pool.maxtotal";
+ public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE =
+ "client.http.connection.pool.maxperroute";
+ public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET =
+ "client.http.connection.timeout.socket";
+ public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_CONNECTION =
+ "client.http.connection.timeout.connection";
+ public static final String PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST =
+ "client.http.connection.timeout.request";
+ public static final String PROP_CONFIG_CLIENT_HTTP_SSL_HOSTNAMEVERIFIER_TRUSTALL =
+ "client.http.ssl.hostnameverifier.trustall";
+
+ public static final String PROP_CONFIG_CLIENT_MODE = "client.authmode";
+ public static final String PROP_CONFIG_CLIENT_AUTH_HTTP_USERNAME = "client.auth.http.username";
+ public static final String PROP_CONFIG_CLIENT_AUTH_HTTP_PASSORD = "client.auth.http.password";
+ public static final String PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_PATH =
+ "client.auth.ssl.keystore.path";
+ public static final String PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_PASSORD =
+ "client.auth.ssl.keystore.password";
+ private static final String PROP_CONFIG_CLIENT_AUTH_SSL_KEYSTORE_NAME =
+ "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";
+
+ // default configuration values
+ public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET = "15";
+ public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_CONNECTION = "15";
+ public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_REQUEST = "30";
+ public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL = "500";
+ public static final String DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE = "100";
+
+ private String defaultConfigurationId = null;
+ private final Map<String, HttpClientBuilder> availableBuilders = new HashMap<>();
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see at.gv.egiz.eaaf.core.impl.utils.IHttpClientFactory#getHttpClient()
+ */
+ @Override
+ public CloseableHttpClient getHttpClient() {
+ return getHttpClient(true);
+
+ }
+
+ @Override
+ public CloseableHttpClient getHttpClient(final boolean followRedirects) {
+ return availableBuilders.get(defaultConfigurationId).setRedirectStrategy(
+ buildRedirectStrategy(followRedirects)).build();
+
+ }
+
+ @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());
+
+ } else {
+ log.debug("Initialize new http-client builder for: {}", config.getFriendlyName());
+
+ //validate configuration object
+ config.validate();
+
+ builder = HttpClients.custom();
+ builder.setDefaultRequestConfig(buildDefaultRequestConfig());
+
+ //inject basic authentication infos
+ injectBasicAuthenticationIfRequired(builder, config);
+
+ //inject authentication if required
+ final LayeredConnectionSocketFactory sslConnectionFactory = getSslContext(config);
+
+ // set pool connection if required
+ injectDefaultConnectionPoolIfRequired(builder, sslConnectionFactory);
+
+ availableBuilders.put(config.getUuid(), builder);
+
+ }
+
+ return builder.setRedirectStrategy(
+ buildRedirectStrategy(config.isFollowHttpRedirects())).build();
+
+ }
+
+ @PostConstruct
+ private void initalize() throws EaafException {
+ final HttpClientConfiguration defaultHttpClientConfig = buildDefaultHttpClientConfiguration();
+
+ // initialize http client
+ log.trace("Initializing default HTTP-Client builder ... ");
+ final HttpClientBuilder defaultHttpClientBuilder = HttpClients.custom();
+
+ // set default request configuration
+ defaultHttpClientBuilder.setDefaultRequestConfig(buildDefaultRequestConfig());
+
+ //inject http basic authentication
+ injectBasicAuthenticationIfRequired(defaultHttpClientBuilder, defaultHttpClientConfig);
+
+ // inject authentication if required
+ final LayeredConnectionSocketFactory sslConnectionFactory =
+ getSslContext(defaultHttpClientConfig);
+
+ // set pool connection if required
+ injectDefaultConnectionPoolIfRequired(defaultHttpClientBuilder, sslConnectionFactory);
+
+ //set default http client builder
+ defaultConfigurationId = defaultHttpClientConfig.getUuid();
+ availableBuilders.put(defaultConfigurationId, defaultHttpClientBuilder);
+
+ }
+
+ 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 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());
+
+ 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());
+
+ } else {
+ log.trace("Injection of Http Basic authentication was skipped");
+
+ }
+
+ }
+
+ @Nonnull
+ private LayeredConnectionSocketFactory getSslContext(final HttpClientConfiguration httpClientConfig)
+ throws EaafException {
+ SSLContext sslContext = null;
+ 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 ... ");
+ sslContext = SSLContexts.createDefault();
+
+ }
+
+ // set hostname verifier
+ HostnameVerifier hostnameVerifier = null;
+ if (httpClientConfig.isDisableHostnameValidation()) {
+ hostnameVerifier = new NoopHostnameVerifier();
+ log.warn("HTTP client-builder deactivates SSL Host-name verification!");
+
+ }
+
+ final LayeredConnectionSocketFactory sslSocketFactory =
+ new SSLConnectionSocketFactory(sslContext, hostnameVerifier);
+ log.debug("HTTP client-builder successfuly initialized");
+ return sslSocketFactory;
+
+ }
+
+ private void injectDefaultConnectionPoolIfRequired(
+ HttpClientBuilder builder, final LayeredConnectionSocketFactory sslConnectionFactory) {
+ if (basicConfig.getBasicConfigurationBoolean(PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_USE,
+ true)) {
+ PoolingHttpClientConnectionManager pool;
+
+ // set socketFactoryRegistry if SSLConnectionFactory is Set
+ if (sslConnectionFactory != null) {
+ final Registry<ConnectionSocketFactory> socketFactoryRegistry =
+ RegistryBuilder.<ConnectionSocketFactory>create()
+ .register("http", PlainConnectionSocketFactory.getSocketFactory())
+ .register("https", sslConnectionFactory).build();
+ log.trace("Inject SSLSocketFactory into pooled connection");
+ pool = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
+
+ } else {
+ pool = new PoolingHttpClientConnectionManager();
+
+ }
+
+ pool.setDefaultMaxPerRoute(Integer.parseInt(
+ basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE,
+ DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXPERROUTE)));
+ pool.setMaxTotal(Integer.parseInt(
+ basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL,
+ DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_POOL_MAXTOTAL)));
+
+ pool.setDefaultSocketConfig(SocketConfig.custom().setSoTimeout(Integer.parseInt(
+ basicConfig.getBasicConfiguration(PROP_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET,
+ DEFAULT_CONFIG_CLIENT_HTTP_CONNECTION_TIMEOUT_SOCKET))
+ * 1000).build());
+
+ 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");
+ 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/http/HttpUtils.java b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java
new file mode 100644
index 00000000..2d514912
--- /dev/null
+++ b/eaaf_core_utils/src/main/java/at/gv/egiz/eaaf/core/impl/http/HttpUtils.java
@@ -0,0 +1,194 @@
+/*
+ * Copyright 2014 Federal Chancellery Austria MOA-ID has been developed in a cooperation between
+ * BRZ, the Federal Chancellery Austria - ICT staff unit, and Graz University of Technology.
+ *
+ * Licensed under the EUPL, Version 1.1 or - as soon they will be approved by the European
+ * Commission - subsequent versions of the EUPL (the "Licence"); You may not use this work except in
+ * compliance with the Licence. You may obtain a copy of the Licence at: http://www.osor.eu/eupl/
+ *
+ * Unless required by applicable law or agreed to in writing, software distributed under the Licence
+ * is distributed on an "AS IS" basis, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
+ * or implied. See the Licence for the specific language governing permissions and limitations under
+ * the Licence.
+ *
+ * This product combines work with different licenses. See the "NOTICE" text file for details on the
+ * various modules and licenses. The "NOTICE" text file is part of the distribution. Any derivative
+ * works that you distribute must include a readable copy of the "NOTICE" text file.
+*/
+
+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.
+ *
+ * @param request HttpServletRequest
+ * @return Server URL including context path (e.g.
+ * http://localhost:8443/moa-id-auth
+ */
+ public static String getBaseUrl(final HttpServletRequest request) {
+ final StringBuffer buffer = new StringBuffer(getServerUrl(request));
+
+ // add context path if available
+ final String contextPath = request.getContextPath();
+ if (!StringUtils.isEmpty(contextPath)) {
+ buffer.append(contextPath);
+ }
+
+ return buffer.toString();
+ }
+
+ /**
+ * Helper method to retrieve server URL.
+ *
+ * @param request HttpServletRequest
+ * @return Server URL (e.g. http://localhost:8443)
+ */
+ public static String getServerUrl(final HttpServletRequest request) {
+ final StringBuffer buffer = new StringBuffer();
+
+ // get protocol
+ final String protocol = request.getScheme();
+ buffer.append(protocol).append("://");
+
+ // server name
+ buffer.append(request.getServerName());
+
+ // add port if necessary
+ final int port = request.getServerPort();
+ if (protocol.equals("http") && port != 80 || protocol.equals("https") && port != 443) {
+ buffer.append(':');
+ buffer.append(port);
+ }
+
+ return buffer.toString();
+ }
+
+ /**
+ * Extract the IDP PublicURLPrefix from authrequest.
+ *
+ * @param req HttpServletRequest
+ * @return PublicURLPrefix which ends always without /
+ */
+ public static String extractAuthUrlFromRequest(final HttpServletRequest req) {
+ String authUrl = req.getScheme() + "://" + req.getServerName();
+ if (req.getScheme().equalsIgnoreCase("https") && req.getServerPort() != 443
+ || req.getScheme().equalsIgnoreCase("http") && req.getServerPort() != 80) {
+ authUrl = authUrl.concat(":" + req.getServerPort());
+ }
+ authUrl = authUrl.concat(req.getContextPath());
+ return authUrl;
+
+ }
+
+ /**
+ * Extract the IDP requested URL from authrequest.
+ *
+ * @param req HttpServletRequest
+ * @return RequestURL which ends always without /
+ */
+ public static String extractAuthServletPathFromRequest(final HttpServletRequest req) {
+ return extractAuthUrlFromRequest(req).concat(req.getServletPath());
+
+ }
+
+ /**
+ * Add a http GET parameter to URL.
+ *
+ * @param url URL
+ * @param paramname Name of the parameter.
+ * @param paramvalue Value of the parameter.
+ * @return
+ */
+ public static String addUrlParameter(final String url, final String paramname,
+ final String paramvalue) {
+ final String param = paramname + "=" + paramvalue;
+ if (url.indexOf("?") < 0) {
+ return url + "?" + param;
+ } else {
+ return url + "&" + param;
+ }
+ }
+
+ /**
+ * 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;
+
+}