diff --git a/CHANGELOG.md b/CHANGELOG.md index 8dd21cc..8500cff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,4 +1,9 @@ +## 1.21.0 (10-06-2024) + +### Novità: 1 +- [#32690](https://parermine.regione.emilia-romagna.it/issues/32690) Introduzione di logica centralizzata per invocazione revocation URL via "single client instance" (DSS) + ## 1.20.0 (06-06-2024) ### Novità: 1 diff --git a/CONTAINER-SCAN-REPORT.md b/CONTAINER-SCAN-REPORT.md index 1385796..be87776 100644 --- a/CONTAINER-SCAN-REPORT.md +++ b/CONTAINER-SCAN-REPORT.md @@ -1,7 +1,7 @@ ## Container scan evidence CVE Image name: registry.ente.regione.emr.it/parer/okd/verifica-firma-eidas:sast -
Run date: Thu Jun 6 18:35:21 CEST 2024 -
Produced by: Job +
Run date: Mon Jun 10 17:26:01 CEST 2024 +
Produced by: Job
CVE founded: 8 | CVE | Description | Severity | Solution | |:---:|:---|:---:|:---| diff --git a/RELEASE-NOTES.md b/RELEASE-NOTES.md index 30dcb68..6690ff9 100644 --- a/RELEASE-NOTES.md +++ b/RELEASE-NOTES.md @@ -1,4 +1,4 @@ -## 1.20.0 (06-06-2024) +## 1.21.0 (10-06-2024) ### Novità: 1 -- [#32661](https://parermine.regione.emilia-romagna.it/issues/32661) Ottimizzazione/Re-factor apache client utilizzato per recupero documento da verificare e parametro per disattivazione verifica SSL +- [#32690](https://parermine.regione.emilia-romagna.it/issues/32690) Introduzione di logica centralizzata per invocazione revocation URL via "single client instance" (DSS) diff --git a/pom.xml b/pom.xml index e471cd5..f3cc814 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ 4.0.0 verifica-firma-eidas - 1.20.1-SNAPSHOT + 1.21.1-SNAPSHOT ${packaging.type} Verifica Firma EIDAS Progetto per effettuare firme e validazioni con librerie DSS (EIDAS) diff --git a/src/main/java/it/eng/parer/eidas/core/bean/CommonsDataHttpClient.java b/src/main/java/it/eng/parer/eidas/core/bean/CommonsDataHttpClient.java new file mode 100644 index 0000000..c0e55d2 --- /dev/null +++ b/src/main/java/it/eng/parer/eidas/core/bean/CommonsDataHttpClient.java @@ -0,0 +1,947 @@ + +package it.eng.parer.eidas.core.bean; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Serializable; +import java.net.URI; +import java.net.URISyntaxException; +import java.security.GeneralSecurityException; +import java.security.KeyStore; +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; + +import javax.net.ssl.HostnameVerifier; + +import org.apache.hc.client5.http.HttpRequestRetryStrategy; +import org.apache.hc.client5.http.auth.AuthScope; +import org.apache.hc.client5.http.auth.Credentials; +import org.apache.hc.client5.http.auth.UsernamePasswordCredentials; +import org.apache.hc.client5.http.classic.methods.HttpUriRequest; +import org.apache.hc.client5.http.classic.methods.HttpUriRequestBase; +import org.apache.hc.client5.http.config.ConnectionConfig; +import org.apache.hc.client5.http.config.RequestConfig; +import org.apache.hc.client5.http.impl.auth.BasicCredentialsProvider; +import org.apache.hc.client5.http.impl.auth.BasicScheme; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.client5.http.impl.classic.HttpClientBuilder; +import org.apache.hc.client5.http.impl.classic.HttpClients; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager; +import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder; +import org.apache.hc.client5.http.io.HttpClientConnectionManager; +import org.apache.hc.client5.http.protocol.HttpClientContext; +import org.apache.hc.client5.http.ssl.DefaultHostnameVerifier; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactory; +import org.apache.hc.client5.http.ssl.SSLConnectionSocketFactoryBuilder; +import org.apache.hc.core5.http.HttpHost; +import org.apache.hc.core5.http.io.HttpClientResponseHandler; +import org.apache.hc.core5.http.io.SocketConfig; +import org.apache.hc.core5.http.protocol.HttpContext; +import org.apache.hc.core5.ssl.SSLContextBuilder; +import org.apache.hc.core5.ssl.TrustStrategy; +import org.apache.hc.core5.util.TimeValue; +import org.apache.hc.core5.util.Timeout; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import eu.europa.esig.dss.model.DSSDocument; +import eu.europa.esig.dss.service.http.commons.CommonsHttpClientResponseHandler; +import eu.europa.esig.dss.service.http.commons.HostConnection; +import eu.europa.esig.dss.service.http.commons.UserCredentials; +import eu.europa.esig.dss.spi.exception.DSSExternalResourceException; +import eu.europa.esig.dss.utils.Utils; + +public class CommonsDataHttpClient implements Serializable { + + private static final long serialVersionUID = 5684332248649660441L; + + private static final Logger LOG = LoggerFactory.getLogger(CommonsDataHttpClient.class); + + /** The default connection timeout (1 minute) */ + private static final Timeout TIMEOUT_CONNECTION = toTimeoutMilliseconds(60000); + + /** The default socket timeout (1 minute) */ + private static final Timeout TIMEOUT_SOCKET = toTimeoutMilliseconds(60000); + + /** The default value of maximum connections in time (20) */ + private static final int CONNECTIONS_MAX_TOTAL = 20; + + /** The default value of maximum connections per route (2) */ + private static final int CONNECTIONS_MAX_PER_ROUTE = 2; + + /** The default connection total time to live (TTL) (1 minute) */ + private static final TimeValue CONNECTION_TIME_TO_LIVE = toTimeValueMilliseconds(60000); + + /** The timeout connection */ + private Timeout timeoutConnection = TIMEOUT_CONNECTION; + + /** The connection request timeout */ + private Timeout timeoutConnectionRequest = TIMEOUT_CONNECTION; + + /** The server response timeout */ + private Timeout timeoutResponse = TIMEOUT_CONNECTION; + + /** The timeout socket */ + private Timeout timeoutSocket = TIMEOUT_SOCKET; + + /** Connection keep alive timeout */ + private TimeValue connectionKeepAlive = CONNECTION_TIME_TO_LIVE; + + /** Maximum connections number in time */ + private int connectionsMaxTotal = CONNECTIONS_MAX_TOTAL; + + /** Maximum connections number per route */ + private int connectionsMaxPerRoute = CONNECTIONS_MAX_PER_ROUTE; + + /** The finite connection total time to live (TTL) */ + private TimeValue connectionTimeToLive = CONNECTION_TIME_TO_LIVE; + + /** Defines if the redirection is enabled */ + private boolean redirectsEnabled = true; + + /** Defines if the default system network properties shall be used */ + private boolean useSystemProperties = false; + + /** Contains rules credentials for authentication to different resources */ + private Map authenticationMap; + + /** + * Used SSL protocol + */ + private String sslProtocol; + + /** + * Keystore for SSL. + */ + private DSSDocument sslKeystore; + + /** + * Keystore's type. + */ + private String sslKeystoreType = KeyStore.getDefaultType(); + + /** + * Keystore's password. + */ + private char[] sslKeystorePassword = new char[] {}; + + /** + * Defines if the keyStore shall be loaded as a trusted material + */ + private boolean loadKeyStoreAsTrustMaterial = false; + + /** + * TrustStore for SSL. + */ + private DSSDocument sslTruststore; + + /** + * Trust store's type + */ + private String sslTruststoreType = KeyStore.getDefaultType(); + + /** + * Truststore's password. + */ + private char[] sslTruststorePassword = new char[] {}; + + /** + * The trust strategy + */ + private transient TrustStrategy trustStrategy; + + /** + * Array of supported SSL protocols + */ + private String[] supportedSSLProtocols; + + /** + * Array of supported SSL Cipher Suites + */ + private String[] supportedSSLCipherSuites; + + /** + * The hostname verifier + */ + private transient HostnameVerifier hostnameVerifier = new DefaultHostnameVerifier(); + + /** + * The connection retry strategy + */ + private transient HttpRequestRetryStrategy retryStrategy; + + /** + * Defines whether the preemptive basic authentication should be used + */ + private boolean preemptiveAuthentication; + + /** + * Processes the HTTP dataHttpClient response and returns byte array in case of success Default: + * {@code CommonsHttpClientResponseHandler} + */ + private transient HttpClientResponseHandler httpClientResponseHandler = new CommonsHttpClientResponseHandler(); + + /** + * Standard dataHttpClient + */ + private transient CloseableHttpClient client; + + /** + * The default constructor for CommonsDataLoader. + */ + public CommonsDataHttpClient() { + // empty + } + + /** + * init method + */ + public void init() { + if (client == null) { + client = createHttpClient(); + } + } + + /** + * destroy method + * + * @throws IOException + * generic exception + */ + public void destroy() throws IOException { + if (client != null) { + client.close(); + } + } + + /** + * Gets the connection timeout. + * + * @return the value (millis) + */ + public int getTimeoutConnection() { + return timeoutConnection.toMillisecondsIntBound(); + } + + /** + * Sets the connection timeout in milliseconds. + * + * A negative value is interpreted as undefined (use system default). + * + * @param timeoutConnection + * the value (millis) + */ + public void setTimeoutConnection(final int timeoutConnection) { + this.timeoutConnection = toTimeoutMilliseconds(timeoutConnection); + } + + /** + * Gets the connection request timeout. + * + * @return the value (millis) + */ + public int getTimeoutConnectionRequest() { + return timeoutConnectionRequest.toMillisecondsIntBound(); + } + + /** + * Sets the connection request in milliseconds. + * + * A negative value is interpreted as undefined (use system default). + * + * @param timeoutConnectionRequest + * the value (millis) + */ + public void setTimeoutConnectionRequest(int timeoutConnectionRequest) { + this.timeoutConnectionRequest = toTimeoutMilliseconds(timeoutConnectionRequest); + } + + /** + * Gets the server response timeout. + * + * @return the value (millis) + */ + public int getTimeoutResponse() { + return timeoutResponse.toMillisecondsIntBound(); + } + + /** + * Sets the server response timeout in milliseconds. + * + * A negative value is interpreted as undefined (use system default). + * + * @param timeoutResponse + * the value (millis) + */ + public void setTimeoutResponse(int timeoutResponse) { + this.timeoutResponse = toTimeoutMilliseconds(timeoutResponse); + } + + /** + * Gets the socket timeout. + * + * @return the value (millis) + */ + public int getTimeoutSocket() { + return timeoutSocket.toMillisecondsIntBound(); + } + + /** + * Sets the socket timeout in milliseconds. + * + * A negative value is interpreted as undefined (use system default). + * + * @param timeoutSocket + * the value (millis) + */ + public void setTimeoutSocket(final int timeoutSocket) { + this.timeoutSocket = toTimeoutMilliseconds(timeoutSocket); + } + + /** + * Gets the connection keep alive timeout. + * + * @return the value (millis) + */ + public int getConnectionKeepAlive() { + return connectionKeepAlive.toMillisecondsIntBound(); + } + + /** + * Sets the connection keep alive timeout in milliseconds. + * + * @param connectionKeepAlive + * the value (millis) + */ + public void setConnectionKeepAlive(int connectionKeepAlive) { + this.connectionKeepAlive = toTimeValueMilliseconds(connectionKeepAlive); + } + + /** + * Gets the maximum connections number. + * + * @return the value (millis) + */ + public int getConnectionsMaxTotal() { + return connectionsMaxTotal; + } + + /** + * Sets the maximum connections number. + * + * @param connectionsMaxTotal + * maximum number of connections + */ + public void setConnectionsMaxTotal(int connectionsMaxTotal) { + this.connectionsMaxTotal = connectionsMaxTotal; + } + + /** + * Gets the maximum connections number per route. + * + * @return maximum number of connections per one route + */ + public int getConnectionsMaxPerRoute() { + return connectionsMaxPerRoute; + } + + /** + * Sets the maximum connections number per route. + * + * @param connectionsMaxPerRoute + * maximum number of connections per one route + */ + public void setConnectionsMaxPerRoute(int connectionsMaxPerRoute) { + this.connectionsMaxPerRoute = connectionsMaxPerRoute; + } + + /** + * Gets the finite connection time to live. + * + * @return connection time to live (millis) + */ + public int getConnectionTimeToLive() { + return connectionTimeToLive.toMillisecondsIntBound(); + } + + /** + * Sets the finite connection total time to live (TTL) in milliseconds. + * + * @param connectionTimeToLive + * the finite connection time to live (millis) + */ + public void setConnectionTimeToLive(int connectionTimeToLive) { + this.connectionTimeToLive = toTimeValueMilliseconds(connectionTimeToLive); + } + + /** + * Gets if redirect is enabled. + * + * @return true if http redirects are allowed + */ + public boolean isRedirectsEnabled() { + return redirectsEnabled; + } + + /** + * Sets if redirect should be enabled. + * + * @param redirectsEnabled + * true if http redirects are allowed + */ + public void setRedirectsEnabled(boolean redirectsEnabled) { + this.redirectsEnabled = redirectsEnabled; + } + + /** + * Gets if the default system network properties shall be used + * + * @return TRUE if the default system network properties shall be used, FALSE otherwise + */ + public boolean isUseSystemProperties() { + return useSystemProperties; + } + + /** + * Sets if the default system network properties shall be used + * + * Default: FALSE (system properties are not used) + * + * NOTE: all other configured property may override the default behavior! + * + * @param useSystemProperties + * if the default system network properties shall be used + */ + public void setUseSystemProperties(boolean useSystemProperties) { + this.useSystemProperties = useSystemProperties; + } + + /** + * This method sets the SSL protocol to be used + * + * @param sslProtocol + * the ssl protocol to be used + */ + public void setSslProtocol(String sslProtocol) { + this.sslProtocol = sslProtocol; + } + + /** + * Sets the SSL KeyStore + * + * @param sslKeyStore + * {@link DSSDocument} + */ + public void setSslKeystore(DSSDocument sslKeyStore) { + this.sslKeystore = sslKeyStore; + } + + /** + * Sets if the KeyStore shall be considered as a trust material (used for SSL connection) + * + * @param loadKeyStoreAsTrustMaterial + * if the KeyStore shall be considered as a trust material + */ + public void setKeyStoreAsTrustMaterial(boolean loadKeyStoreAsTrustMaterial) { + this.loadKeyStoreAsTrustMaterial = loadKeyStoreAsTrustMaterial; + } + + /** + * Sets the SSL KeyStore type + * + * @param sslKeystoreType + * {@link String} + */ + public void setSslKeystoreType(String sslKeystoreType) { + this.sslKeystoreType = sslKeystoreType; + } + + /** + * Sets the KeyStore password. Please note that the password shall be the same for the keystore and the extraction + * of a corresponding key. + * + * @param sslKeystorePassword + * char array representing the password + */ + public void setSslKeystorePassword(char[] sslKeystorePassword) { + this.sslKeystorePassword = sslKeystorePassword; + } + + /** + * Sets the SSL trust store + * + * NOTE: different from KeyStore! + * + * @param sslTrustStore + * {@link DSSDocument} + */ + public void setSslTruststore(DSSDocument sslTrustStore) { + this.sslTruststore = sslTrustStore; + } + + /** + * Sets the password for SSL truststore + * + * @param sslTruststorePassword + * char array representing a password string + */ + public void setSslTruststorePassword(char[] sslTruststorePassword) { + this.sslTruststorePassword = sslTruststorePassword; + } + + /** + * Sets the SSL TrustStore type + * + * @param sslTruststoreType + * {@link String} + */ + public void setSslTruststoreType(String sslTruststoreType) { + this.sslTruststoreType = sslTruststoreType; + } + + /** + * Returns the current instance of the authentication map + * + * @return a map between {@link HostConnection} and {@link UserCredentials} + */ + public Map getAuthenticationMap() { + if (authenticationMap == null) { + authenticationMap = new HashMap<>(); + } + return authenticationMap; + } + + /** + * Sets the authentication map + * + * NOTE: this method overrides the current instance of {@code authenticationMap} + * + * @param authenticationMap + * a map between {@link HostConnection} and {@link UserCredentials} + */ + public void setAuthenticationMap(Map authenticationMap) { + this.authenticationMap = authenticationMap; + } + + /** + * Adds authentication credentials to the existing {@code authenticationMap} + * + * @param hostConnection + * host connection details + * @param userCredentials + * user login credentials + * + * @return this (for fluent addAuthentication) + */ + public CommonsDataHttpClient addAuthentication(HostConnection hostConnection, UserCredentials userCredentials) { + Map authenticationMap = getAuthenticationMap(); + authenticationMap.put(hostConnection, userCredentials); + return this; + } + + /** + * Sets whether the preemptive authentication should be used. When set to TRUE, the dataHttpClient sends + * authentication details (i.e. user credentials) within the initial request to the remote host, instead of sending + * the credentials only after a request from the host. Please note that the preemptive authentication should not be + * used over an insecure connection. Default : FALSE (preemptive authentication is not used) + * + * @param preemptiveAuthentication + * whether the preemptive authentication should be used + */ + public void setPreemptiveAuthentication(boolean preemptiveAuthentication) { + this.preemptiveAuthentication = preemptiveAuthentication; + } + + /** + * Adds authentication credentials to the existing {@code authenticationMap} + * + * @param host + * host + * @param port + * port + * @param scheme + * scheme + * @param login + * login + * @param password + * password + * + * @return this (for fluent addAuthentication) + */ + public CommonsDataHttpClient addAuthentication(final String host, final int port, final String scheme, + final String login, final char[] password) { + final HostConnection hostConnection = new HostConnection(host, port, scheme); + final UserCredentials userCredentials = new UserCredentials(login, password); + return addAuthentication(hostConnection, userCredentials); + } + + /** + * Sets a custom retry strategy + * + * @param retryStrategy + * {@link HttpRequestRetryStrategy} + */ + public void setRetryStrategy(final HttpRequestRetryStrategy retryStrategy) { + this.retryStrategy = retryStrategy; + } + + /** + * Gets supported SSL protocols + * + * @return an array if {@link String}s + */ + public String[] getSupportedSSLProtocols() { + return supportedSSLProtocols; + } + + /** + * Sets supported SSL protocols + * + * @param supportedSSLProtocols + * an array if {@link String}s + */ + public void setSupportedSSLProtocols(String[] supportedSSLProtocols) { + this.supportedSSLProtocols = supportedSSLProtocols; + } + + /** + * Gets supported SSL Cipher Suites + * + * @return an array if {@link String}s + */ + public String[] getSupportedSSLCipherSuites() { + return supportedSSLCipherSuites; + } + + /** + * Sets supported SSL Cipher Suites + * + * @param supportedSSLCipherSuites + * an array if {@link String}s + */ + public void setSupportedSSLCipherSuites(String[] supportedSSLCipherSuites) { + this.supportedSSLCipherSuites = supportedSSLCipherSuites; + } + + /** + * Gets the hostname verifier + * + * @return {@link HostnameVerifier} + */ + public HostnameVerifier getHostnameVerifier() { + return hostnameVerifier; + } + + /** + * Sets a custom {@code HostnameVerifier} + * + * @param hostnameVerifier + * {@link HostnameVerifier} + */ + public void setHostnameVerifier(HostnameVerifier hostnameVerifier) { + this.hostnameVerifier = hostnameVerifier; + } + + /** + * Gets the TrustStrategy + * + * @return {@link TrustStrategy} + */ + public TrustStrategy getTrustStrategy() { + return trustStrategy; + } + + /** + * Sets the {@code TrustStrategy} + * + * @param trustStrategy + * {@link TrustStrategy} + */ + public void setTrustStrategy(TrustStrategy trustStrategy) { + this.trustStrategy = trustStrategy; + } + + /** + * Returns the {@code HttpClientResponseHandler} response handler + * + * @return {@link HttpClientResponseHandler} + */ + public HttpClientResponseHandler getHttpClientResponseHandler() { + return httpClientResponseHandler; + } + + /** + * Sets the {@code HttpClientResponseHandler} response handler performing a processing of an HTTP + * dataHttpClient response and returns a byte array in case of success. + * + * @param httpClientResponseHandler + * {@link HttpClientResponseHandler} + */ + public void setHttpClientResponseHandler(HttpClientResponseHandler httpClientResponseHandler) { + Objects.requireNonNull(httpClientResponseHandler, "HttpClientResponseHandler cannot be null!"); + this.httpClientResponseHandler = httpClientResponseHandler; + } + + /** + * Gets the {@code HttpHost} + * + * @param httpRequest + * {@link HttpUriRequest} + * + * @return {@link HttpHost} + */ + protected HttpHost getHttpHost(final HttpUriRequest httpRequest) { + try { + final URI uri = httpRequest.getUri(); + return new HttpHost(uri.getScheme(), uri.getHost(), uri.getPort()); + } catch (URISyntaxException e) { + throw new DSSExternalResourceException(String.format("Invalid URI : %s", e.getMessage()), e); + } + } + + /** + * Gets the {@code HttpContext} + * + * @param httpHost + * {@link HttpHost} + * + * @return {@link HttpContext} + */ + protected HttpContext getHttpContext(HttpHost httpHost) { + HttpClientContext localContext = HttpClientContext.create(); + localContext = configurePreemptiveAuthentication(localContext, httpHost); + return localContext; + } + + /** + * This method is used to configure preemptive authentication process for {@code HttpClientContext}, when required + * + * @param localContext + * {@link HttpClientContext} + * @param httpHost + * {@link HttpHost} + * + * @return {@link HttpClientContext} + */ + protected HttpClientContext configurePreemptiveAuthentication(HttpClientContext localContext, HttpHost httpHost) { + if (preemptiveAuthentication && Utils.isMapNotEmpty(getAuthenticationMap())) { + Credentials credentials = getCredentialsProvider().getCredentials(new AuthScope(httpHost), localContext); + BasicScheme basicScheme = new BasicScheme(); + basicScheme.initPreemptive(credentials); + localContext.resetAuthExchange(httpHost, basicScheme); + } + return localContext; + } + + /** + * Closes all the parameters quietly + * + * @param httpRequest + * {@link HttpUriRequestBase} + * @param client + * {@link CloseableHttpClient} + */ + protected void closeQuietly(HttpUriRequestBase httpRequest, CloseableHttpClient client) { + try { + if (httpRequest != null) { + httpRequest.cancel(); + } + } finally { + Utils.closeQuietly(client); + } + } + + private HttpClientConnectionManager getConnectionManager() { + final PoolingHttpClientConnectionManagerBuilder builder = PoolingHttpClientConnectionManagerBuilder.create() + .setSSLSocketFactory(getConnectionSocketFactoryHttps()).setDefaultSocketConfig(getSocketConfig()) + .setMaxConnTotal(getConnectionsMaxTotal()).setMaxConnPerRoute(getConnectionsMaxPerRoute()); + + final ConnectionConfig.Builder connectionConfigBuilder = ConnectionConfig.custom() + .setConnectTimeout(timeoutConnection).setTimeToLive(connectionTimeToLive); + + final PoolingHttpClientConnectionManager connectionManager = builder.build(); + connectionManager.setDefaultConnectionConfig(connectionConfigBuilder.build()); + + LOG.debug("PoolingHttpClientConnectionManager: max total: {}", connectionManager.getMaxTotal()); + LOG.debug("PoolingHttpClientConnectionManager: max per route: {}", connectionManager.getDefaultMaxPerRoute()); + + return connectionManager; + } + + private SocketConfig getSocketConfig() { + SocketConfig.Builder socketConfigBuilder = SocketConfig.custom(); + socketConfigBuilder.setSoTimeout(timeoutSocket); + return socketConfigBuilder.build(); + } + + private SSLConnectionSocketFactory getConnectionSocketFactoryHttps() { + try { + SSLContextBuilder sslContextBuilder = SSLContextBuilder.create(); + sslContextBuilder.setProtocol(sslProtocol); + + final TrustStrategy trustStrategy = getTrustStrategy(); + if (trustStrategy != null) { + LOG.debug("Set the TrustStrategy"); + sslContextBuilder.loadTrustMaterial(null, trustStrategy); + } + + final KeyStore sslTrustStore = getSSLTrustStore(); + if (sslTrustStore != null) { + LOG.debug("Set the SSL trust store as trust materials"); + sslContextBuilder.loadTrustMaterial(sslTrustStore, trustStrategy); + } + + final KeyStore sslKeystore = getSSLKeyStore(); + if (sslKeystore != null) { + LOG.debug("Set the SSL keystore as key materials"); + sslContextBuilder.loadKeyMaterial(sslKeystore, sslKeystorePassword); + if (loadKeyStoreAsTrustMaterial) { + LOG.debug("Set the SSL keystore as trust materials"); + sslContextBuilder.loadTrustMaterial(sslKeystore, trustStrategy); + } + } + + SSLConnectionSocketFactoryBuilder sslConnectionSocketFactoryBuilder = new SSLConnectionSocketFactoryBuilder(); + return sslConnectionSocketFactoryBuilder.setSslContext(sslContextBuilder.build()) + .setTlsVersions(getSupportedSSLProtocols()).setCiphers(getSupportedSSLCipherSuites()) + .setHostnameVerifier(getHostnameVerifier()).build(); + + } catch (final Exception e) { + throw new IllegalArgumentException("Unable to configure the SSLContext/SSLConnectionSocketFactory", e); + } + } + + /** + * Gets the SSL KeyStore + * + * @return {@link KeyStore} + * + * @throws IOException + * if IOException occurs + * @throws GeneralSecurityException + * if GeneralSecurityException occurs + */ + protected KeyStore getSSLKeyStore() throws IOException, GeneralSecurityException { + return loadKeyStore(sslKeystore, sslKeystoreType, sslKeystorePassword); + } + + /** + * Gets the SSL Trusted KeyStore + * + * @return {@link KeyStore} + * + * @throws IOException + * if IOException occurs + * @throws GeneralSecurityException + * if GeneralSecurityException occurs + */ + protected KeyStore getSSLTrustStore() throws IOException, GeneralSecurityException { + return loadKeyStore(sslTruststore, sslTruststoreType, sslTruststorePassword); + } + + private KeyStore loadKeyStore(DSSDocument store, String type, char[] password) + throws IOException, GeneralSecurityException { + if (store != null) { + try (InputStream is = store.openStream()) { + KeyStore ks = KeyStore.getInstance(type); + ks.load(is, password); + return ks; + } + } else { + return null; + } + } + + /** + * Gets the {@code HttpClientBuilder} + * + * + * @return {@link HttpClientBuilder} + */ + protected HttpClientBuilder getHttpClientBuilder() { + HttpClientBuilder httpClientBuilder = HttpClients.custom(); + + if (useSystemProperties) { + httpClientBuilder.useSystemProperties(); + } + + httpClientBuilder = configCredentials(httpClientBuilder); + + final RequestConfig.Builder requestConfigBuilder = RequestConfig.custom() + .setConnectionRequestTimeout(timeoutConnectionRequest).setResponseTimeout(timeoutResponse) + .setConnectionKeepAlive(connectionKeepAlive).setRedirectsEnabled(redirectsEnabled); + + httpClientBuilder.setConnectionManager(getConnectionManager()) + .setDefaultRequestConfig(requestConfigBuilder.build()).setRetryStrategy(retryStrategy); + + return httpClientBuilder; + } + + /** + * Create the HTTP dataHttpClient + * + * @return {@link CloseableHttpClient} + */ + protected CloseableHttpClient createHttpClient() { + return getHttpClientBuilder().build(); + } + + /** + * Defines the Credentials + * + * @param httpClientBuilder + * {@link HttpClientBuilder} + * @param url + * {@link String} + * + * @return {@link HttpClientBuilder} + */ + private HttpClientBuilder configCredentials(HttpClientBuilder httpClientBuilder) { + final BasicCredentialsProvider credentialsProvider = getCredentialsProvider(); + httpClientBuilder.setDefaultCredentialsProvider(credentialsProvider); + return httpClientBuilder; + } + + /** + * Builds and returns a {@code BasicCredentialsProvider} configured with {@code authenticationMap} + * + * @return {@link BasicCredentialsProvider} + */ + protected BasicCredentialsProvider getCredentialsProvider() { + final BasicCredentialsProvider credentialsProvider = new BasicCredentialsProvider(); + for (final Map.Entry entry : getAuthenticationMap().entrySet()) { + final HostConnection hostConnection = entry.getKey(); + final UserCredentials userCredentials = entry.getValue(); + final AuthScope authscope = new AuthScope(hostConnection.getProtocol(), hostConnection.getHost(), + hostConnection.getPort(), hostConnection.getRealm(), hostConnection.getScheme()); + + final UsernamePasswordCredentials usernamePasswordCredentials = new UsernamePasswordCredentials( + userCredentials.getUsername(), userCredentials.getPassword()); + credentialsProvider.setCredentials(authscope, usernamePasswordCredentials); + } + return credentialsProvider; + } + + private static Timeout toTimeoutMilliseconds(int millis) { + if (millis < 0) { + LOG.info("A negative timeout has been provided. Use system default."); + return null; + } + return Timeout.ofMilliseconds(millis); + } + + private static TimeValue toTimeValueMilliseconds(int millis) { + return TimeValue.ofMilliseconds(millis); + } + + /** + * Standard HTTP Apache Client + * + * @return dataHttpClient + */ + public CloseableHttpClient getHttpClient() { + return client; + } + +} diff --git a/src/main/java/it/eng/parer/eidas/core/bean/CommonsDataLoaderExt.java b/src/main/java/it/eng/parer/eidas/core/bean/CommonsDataLoaderExt.java index 818bcb3..e51b55c 100644 --- a/src/main/java/it/eng/parer/eidas/core/bean/CommonsDataLoaderExt.java +++ b/src/main/java/it/eng/parer/eidas/core/bean/CommonsDataLoaderExt.java @@ -17,14 +17,27 @@ package it.eng.parer.eidas.core.bean; +import java.io.IOException; + +import org.apache.hc.client5.http.classic.methods.HttpUriRequest; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import eu.europa.esig.dss.service.http.commons.CommonsDataLoader; -import it.eng.parer.eidas.core.util.Constants; public class CommonsDataLoaderExt extends CommonsDataLoader implements CustomDataLoaderExt { private static final long serialVersionUID = -272512490031055464L; - private String ldapTimeoutConnection = Constants.TIMEOUT_LDAP_CONNECTION; + private static final Logger LOG = LoggerFactory.getLogger(CommonsDataLoaderExt.class); + + // ** LDAP + + private String ldapTimeoutConnection = TIMEOUT_LDAP_CONNECTION; + + /** The Commons HTTP dataHttpClient */ + private CommonsDataHttpClient dataHttpClient; /** * Sovrascritto il metodo del padre in quanto non implementava un TIMEOUT nelle chiamate LDAP @@ -51,4 +64,36 @@ public void setLdapTimeoutConnection(String ldapTimeoutConnection) { this.ldapTimeoutConnection = ldapTimeoutConnection; } + /* HTTP GET */ + @Override + protected byte[] httpGet(String url) { + return customHttpGet(url); + } + + /* HTTP POST */ + @Override + public byte[] post(String url, byte[] content) { + return customPost(url, content); + } + + @Override + public byte[] execute(CloseableHttpClient client, HttpUriRequest httpRequest) throws IOException { + return super.execute(client, httpRequest); + } + + @Override + public void setCommonsDataHttpClient(CommonsDataHttpClient dataHttpClient) { + this.dataHttpClient = dataHttpClient; + } + + @Override + public CommonsDataHttpClient getCommonsDataHttpClient() { + return dataHttpClient; + } + + @Override + public Logger logger() { + return LOG; + } + } diff --git a/src/main/java/it/eng/parer/eidas/core/bean/CustomDataLoaderExt.java b/src/main/java/it/eng/parer/eidas/core/bean/CustomDataLoaderExt.java index 3f59b73..d2d90cd 100644 --- a/src/main/java/it/eng/parer/eidas/core/bean/CustomDataLoaderExt.java +++ b/src/main/java/it/eng/parer/eidas/core/bean/CustomDataLoaderExt.java @@ -17,6 +17,10 @@ package it.eng.parer.eidas.core.bean; +import java.io.ByteArrayInputStream; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; import java.util.Hashtable; import java.util.StringTokenizer; @@ -26,13 +30,28 @@ import javax.naming.directory.DirContext; import javax.naming.directory.InitialDirContext; +import org.apache.hc.client5.http.classic.methods.HttpGet; +import org.apache.hc.client5.http.classic.methods.HttpPost; +import org.apache.hc.client5.http.classic.methods.HttpUriRequest; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.apache.hc.core5.http.ContentType; +import org.apache.hc.core5.http.HttpEntity; +import org.apache.hc.core5.http.io.entity.BufferedHttpEntity; +import org.apache.hc.core5.http.io.entity.InputStreamEntity; +import org.slf4j.Logger; + import eu.europa.esig.dss.model.DSSException; import eu.europa.esig.dss.service.http.commons.LdapURLUtils; +import eu.europa.esig.dss.spi.DSSUtils; import eu.europa.esig.dss.spi.exception.DSSExternalResourceException; import eu.europa.esig.dss.utils.Utils; public interface CustomDataLoaderExt { + static final String CONTENT_TYPE = "Content-Type"; + + static final String TIMEOUT_LDAP_CONNECTION = "6000"; + /** * Extendend OCSPDataLoader method, not implemented TIMEOUT on LDPA call * @@ -92,4 +111,89 @@ default byte[] customLdapGet(String urlString) { public String getLdapTimeoutConnection(); + /* CUSTOM DATA LOADING HTTP */ + + public void setCommonsDataHttpClient(CommonsDataHttpClient dataHttpClient); + + public CommonsDataHttpClient getCommonsDataHttpClient(); + + /* apache dataHttpClient management */ + + default byte[] customPost(String url, byte[] content) { + logger().debug("Fetching data via POST from url {}", url); + + HttpPost httpRequest = null; + // The length for the InputStreamEntity is needed, because some receivers (on + // the other side) + // need this information. + // To determine the length, we cannot read the content-stream up to the end and + // re-use it afterwards. + // This is because, it may not be possible to reset the stream (= go to position + // 0). + // So, the solution is to cache temporarily the complete content data (as we do + // not expect much here) in + // a byte-array. + try (final ByteArrayInputStream bis = new ByteArrayInputStream(content);) { + final URI uri = URI.create(Utils.trim(url)); + httpRequest = new HttpPost(uri); + + final HttpEntity httpEntity = new InputStreamEntity(bis, content.length, + toContentTypeExt(getContentType())); + final HttpEntity requestEntity = new BufferedHttpEntity(httpEntity); + httpRequest.setEntity(requestEntity); + + return execute(getCommonsDataHttpClient().getHttpClient(), httpRequest); + + } catch (IOException e) { + throw new DSSExternalResourceException( + String.format("Unable to process POST call for url [%s]. Reason : [%s]", url, e.getMessage()), e); + + } finally { + if (httpRequest != null) { + httpRequest.cancel(); + } + } + } + + default byte[] customHttpGet(String url) { + HttpGet httpRequest = null; + + try { + httpRequest = customGetHttpRequest(url); + return execute(getCommonsDataHttpClient().getHttpClient(), httpRequest); + + } catch (URISyntaxException | IOException e) { + throw new DSSExternalResourceException(String.format( + "Unable to process GET call for url [%s]. Reason : [%s]", url, DSSUtils.getExceptionMessage(e)), e); + + } finally { + if (httpRequest != null) { + httpRequest.cancel(); + } + } + } + + default HttpGet customGetHttpRequest(String url) throws URISyntaxException { + final URI uri = new URI(Utils.trim(url)); + HttpGet httpRequest = new HttpGet(uri); + if (getContentType() != null) { + httpRequest.setHeader(CONTENT_TYPE, getContentType()); + } + return httpRequest; + } + + default ContentType toContentTypeExt(String contentTypeString) { + return Utils.isStringNotBlank(contentTypeString) ? ContentType.create(contentTypeString) : null; + } + + public Logger logger(); + + /* + * define standard getter & setter (inherint from {@link CommonsDataLoader}) + */ + + public byte[] execute(final CloseableHttpClient client, final HttpUriRequest httpRequest) throws IOException; + + public String getContentType(); + } diff --git a/src/main/java/it/eng/parer/eidas/core/bean/OCSPDataLoaderExt.java b/src/main/java/it/eng/parer/eidas/core/bean/OCSPDataLoaderExt.java index 0dee77c..10acb34 100644 --- a/src/main/java/it/eng/parer/eidas/core/bean/OCSPDataLoaderExt.java +++ b/src/main/java/it/eng/parer/eidas/core/bean/OCSPDataLoaderExt.java @@ -17,8 +17,14 @@ package it.eng.parer.eidas.core.bean; +import java.io.IOException; + +import org.apache.hc.client5.http.classic.methods.HttpUriRequest; +import org.apache.hc.client5.http.impl.classic.CloseableHttpClient; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import eu.europa.esig.dss.service.http.commons.OCSPDataLoader; -import it.eng.parer.eidas.core.util.Constants; public class OCSPDataLoaderExt extends OCSPDataLoader implements CustomDataLoaderExt { @@ -27,7 +33,12 @@ public class OCSPDataLoaderExt extends OCSPDataLoader implements CustomDataLoade */ private static final long serialVersionUID = 2497778964600711396L; - private String ldapTimeoutConnection = Constants.TIMEOUT_LDAP_CONNECTION; + private static final Logger LOG = LoggerFactory.getLogger(OCSPDataLoaderExt.class); + + private String ldapTimeoutConnection = TIMEOUT_LDAP_CONNECTION; + + /** The Commons HTTP dataHttpClient */ + private CommonsDataHttpClient dataHttpClient; /** * Extendend OCSPDataLoader method, not implemented TIMEOUT on LDAP call @@ -55,4 +66,36 @@ public void setLdapTimeoutConnection(String ldapTimeoutConnection) { this.ldapTimeoutConnection = ldapTimeoutConnection; } + /* HTTP GET */ + @Override + protected byte[] httpGet(String url) { + return customHttpGet(url); + } + + /* HTTP POST */ + @Override + public byte[] post(String url, byte[] content) { + return customPost(url, content); + } + + @Override + public byte[] execute(CloseableHttpClient client, HttpUriRequest httpRequest) throws IOException { + return super.execute(client, httpRequest); + } + + @Override + public void setCommonsDataHttpClient(CommonsDataHttpClient dataHttpClient) { + this.dataHttpClient = dataHttpClient; + } + + @Override + public CommonsDataHttpClient getCommonsDataHttpClient() { + return dataHttpClient; + } + + @Override + public Logger logger() { + return LOG; + } + } diff --git a/src/main/java/it/eng/parer/eidas/core/helper/EidasHelper.java b/src/main/java/it/eng/parer/eidas/core/helper/EidasHelper.java index 241282f..95d024c 100644 --- a/src/main/java/it/eng/parer/eidas/core/helper/EidasHelper.java +++ b/src/main/java/it/eng/parer/eidas/core/helper/EidasHelper.java @@ -37,10 +37,8 @@ import java.nio.file.attribute.FileAttribute; import java.nio.file.attribute.PosixFilePermission; import java.nio.file.attribute.PosixFilePermissions; -import java.time.Duration; import java.util.List; import java.util.Set; -import java.util.concurrent.TimeUnit; import javax.xml.XMLConstants; import javax.xml.parsers.DocumentBuilder; @@ -60,24 +58,18 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; -import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.info.BuildProperties; import org.springframework.core.env.Environment; -import org.springframework.core.io.buffer.DataBuffer; -import org.springframework.core.io.buffer.DataBufferUtils; import org.springframework.stereotype.Component; -import org.springframework.web.reactive.function.client.WebClient; import eu.europa.esig.dss.enumerations.MimeTypeEnum; import eu.europa.esig.dss.model.DSSDocument; import eu.europa.esig.dss.spi.DSSUtils; -import it.eng.parer.eidas.core.util.Constants.URIClientType; +import it.eng.parer.eidas.core.bean.CommonsDataHttpClient; import it.eng.parer.eidas.model.EidasDataToValidateMetadata; import it.eng.parer.eidas.model.EidasRemoteDocument; import it.eng.parer.eidas.model.exception.EidasParerException; import it.eng.parer.eidas.model.exception.ParerError; -import reactor.core.publisher.Flux; -import reactor.util.retry.Retry; @Component public class EidasHelper { @@ -100,48 +92,7 @@ public class EidasHelper { BuildProperties buildProperties; @Autowired - ApacheClientHelper apacheClientHelper; - - @Value("${parer.eidas.uriloader.client-type:httpclient}") - URIClientType uRIClientType; - - /* - * Flux+Mono config - */ - // default 60 s - @Value("${parer.eidas.uriloader.webclient.timeout:60}") - long webClientTimeout; - - // default 5 times - @Value("${parer.eidas.uriloader.webclient.backoff:5}") - long webClientBackoff; - - // default 3 s - @Value("${parer.eidas.uriloader.webclient.backofftime:3}") - long webClientBackoffTime; - - /* - * Standard httpclient - */ - // default 60 s - @Value("${parer.eidas.uriloader.httpclient.timeout:60}") - long httpClientTimeout; - - // default 60 s - @Value("${parer.eidas.uriloader.httpclient.timeoutsocket:60}") - int httpClientSocketTimeout; - - // default 4 - @Value("${parer.eidas.uriloader.httpclient.connectionsmaxperroute:4}") - int httpClientConnectionsmaxperroute; - - // default 40 - @Value("${parer.eidas.uriloader.httpclient.connectionsmax:40}") - int httpClientConnectionsmax; - - // default 60s - @Value("${parer.eidas.uriloader.httpclient.timetolive:60}") - long httpClientTimeToLive; + CommonsDataHttpClient dataHttpClient; public String buildversion() { return env.getProperty(BUILD_VERSION); @@ -420,37 +371,11 @@ private Path readBase64EncodedFile(String prefix, InputStream is) throws IOExcep } public void getResourceFromURI(URI signedResource, Path localPath) throws IOException { - if (uRIClientType.equals(URIClientType.HTTPCLIENT)) { - getWithCommonHttpclient(signedResource, localPath); - } else { - getWithWebClient(signedResource, localPath); - } - } - - private void getWithWebClient(URI signedResource, Path localPath) throws IOException { - try { - // Attenzione, se al posto dell'uri viene utilizzata una stringa ci possono - // essere problemi di conversione - // dei - // caratteri - Flux dataBuffer = WebClient.create().get().uri(signedResource).retrieve() - .bodyToFlux(DataBuffer.class); - // scarica sul local path provando 5 volte aspettando almeno 3 secondi tra un - // prova e l'altra - DataBufferUtils.write(dataBuffer, localPath).timeout(Duration.ofSeconds(webClientTimeout)) - .retryWhen(Retry.backoff(webClientBackoff, Duration.ofSeconds(webClientBackoffTime))).share() - .block(); - } catch (Exception ex) { - throw new IOException("Impossibile recuperare il documento da URI", ex); - } - } - - private void getWithCommonHttpclient(URI signedResource, Path localPath) throws IOException { - try (ClassicHttpResponse response = apacheClientHelper.client().executeOpen(null, new HttpGet(signedResource), - null); FileOutputStream out = new FileOutputStream(localPath.toFile());) { + try (ClassicHttpResponse response = dataHttpClient.getHttpClient().executeOpen(null, + new HttpGet(signedResource), null); FileOutputStream out = new FileOutputStream(localPath.toFile());) { // - IOUtils.copy(response.getEntity().getContent(), out); + IOUtils.copyLarge(response.getEntity().getContent(), out); } } diff --git a/src/main/java/it/eng/parer/eidas/core/service/CustomRemoteDocumentValidationImpl.java b/src/main/java/it/eng/parer/eidas/core/service/CustomRemoteDocumentValidationImpl.java index 11fbd23..857a359 100644 --- a/src/main/java/it/eng/parer/eidas/core/service/CustomRemoteDocumentValidationImpl.java +++ b/src/main/java/it/eng/parer/eidas/core/service/CustomRemoteDocumentValidationImpl.java @@ -511,7 +511,7 @@ private EidasWSReportsDTOTree createRoot(DSSDocument signedDocument, Reports rep /** * Vedi issue https://gitlab.ente.regione.emr.it/parer/okd/verifica-firma-eidas/issues/7 * - * Per il momento il validation report non viene restituito al client + * Per il momento il validation report non viene restituito al dataHttpClient */ WSReportsDTO wsdto = new WSReportsDTO(reports.getDiagnosticDataJaxb(), reports.getSimpleReportJaxb(), reports.getDetailedReportJaxb()); diff --git a/src/main/java/it/eng/parer/eidas/core/util/Constants.java b/src/main/java/it/eng/parer/eidas/core/util/Constants.java index 557c805..91e7d0a 100644 --- a/src/main/java/it/eng/parer/eidas/core/util/Constants.java +++ b/src/main/java/it/eng/parer/eidas/core/util/Constants.java @@ -37,9 +37,6 @@ private Constants() { public static final String BUILD_TIME = "git.commit.time"; public static final String DSS_VERSION = "dss.version"; - /* default configuration */ - public static final String TIMEOUT_LDAP_CONNECTION = "6000"; - public static final String TMP_FILE_SUFFIX = "-eidasvf.tmp"; /* default error message on advice handler */ diff --git a/src/main/java/it/eng/parer/eidas/web/config/AdviceHandler.java b/src/main/java/it/eng/parer/eidas/web/config/AdviceHandler.java index 467a38a..035c9bf 100644 --- a/src/main/java/it/eng/parer/eidas/web/config/AdviceHandler.java +++ b/src/main/java/it/eng/parer/eidas/web/config/AdviceHandler.java @@ -54,8 +54,8 @@ public class AdviceHandler { /* * Aggiunto log al fine di loggare i casi di generiche eccezioni ossia generate dopo l'esecuzione del servizio di - * verifica firma (o prima quando si valuta la risposta del client), ma che comunque in generale non sono gestite - * (EidasParerException) all'interno dell'implementazione dell'endpoint. + * verifica firma (o prima quando si valuta la risposta del dataHttpClient), ma che comunque in generale non sono + * gestite (EidasParerException) all'interno dell'implementazione dell'endpoint. */ private static final Logger log = LoggerFactory.getLogger(AdviceHandler.class); diff --git a/src/main/java/it/eng/parer/eidas/web/config/AppConfiguration.java b/src/main/java/it/eng/parer/eidas/web/config/AppConfiguration.java index a178a4d..184963d 100644 --- a/src/main/java/it/eng/parer/eidas/web/config/AppConfiguration.java +++ b/src/main/java/it/eng/parer/eidas/web/config/AppConfiguration.java @@ -91,7 +91,7 @@ public MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter() mapper.configure(DeserializationFeature.ACCEPT_SINGLE_VALUE_AS_ARRAY, true); MappingJackson2HttpMessageConverter mappingJackson2HttpMessageConverter = new MappingJackson2HttpMessageConverter( mapper); - // Aggiungo i media type text/plain per supportare client come jmeter + // Aggiungo i media type text/plain per supportare dataHttpClient come jmeter List supportedMediaTypes = new ArrayList<>( mappingJackson2HttpMessageConverter.getSupportedMediaTypes()); supportedMediaTypes.add(new MediaType(MediaType.TEXT_PLAIN, StandardCharsets.UTF_8)); diff --git a/src/main/java/it/eng/parer/eidas/web/config/DSSBeanConfig.java b/src/main/java/it/eng/parer/eidas/web/config/DSSBeanConfig.java index 2906d01..28220ce 100644 --- a/src/main/java/it/eng/parer/eidas/web/config/DSSBeanConfig.java +++ b/src/main/java/it/eng/parer/eidas/web/config/DSSBeanConfig.java @@ -78,6 +78,7 @@ import eu.europa.esig.dss.ws.signature.common.RemoteTrustedListSignatureServiceImpl; import eu.europa.esig.dss.ws.validation.common.RemoteDocumentValidationService; import eu.europa.esig.dss.xades.signature.XAdESService; +import it.eng.parer.eidas.core.bean.CommonsDataHttpClient; import it.eng.parer.eidas.core.bean.CommonsDataLoaderExt; import it.eng.parer.eidas.core.bean.OCSPDataLoaderExt; import it.eng.parer.eidas.core.service.CustomRemoteDocumentValidationImpl; @@ -160,12 +161,12 @@ public class DSSBeanConfig { @Value("${revoke.removeExpired.enabled:true}") private boolean revokeRemoveExpired; - /* in ms */ - @Value("${dataloader.timeoutconnection:120000}") + /* in ms (5m) */ + @Value("${dataloader.timeoutconnection:300000}") private int timeoutConnection; - /* in ms */ - @Value("${dataloader.timeoutsocket:120000}") + /* in ms (5m) */ + @Value("${dataloader.timeoutsocket:300000}") private int timeoutSocket; @Value("${dataloader.connectionsmaxtotal:40}") @@ -174,12 +175,12 @@ public class DSSBeanConfig { @Value("${dataloader.connectionsmaxperroute:4}") private int connectionsMaxPerRoute; - /* in ms */ - @Value("${dataloader.connectiontimetolive:120000}") + /* in ms (5m) */ + @Value("${dataloader.connectiontimetolive:300000}") private int connectionTimeToLive; - /* in ms */ - @Value("${dataloader.ldaptimeoutconnection:120000}") + /* in ms (5m) */ + @Value("${dataloader.ldaptimeoutconnection:300000}") private String ldapTimeoutConnection; @Value("${cache.enabled:true}") @@ -189,17 +190,26 @@ public class DSSBeanConfig { @Value("${cache.file.path:}") private String cacheFilePath; + /** CUSTOM HTTP CLIENT ! **/ + @Bean(initMethod = "init", destroyMethod = "destroy") + public CommonsDataHttpClient dataHttpClient() { + CommonsDataHttpClient dataClient = new CommonsDataHttpClient(); + // NOTA timeout impostabile (da configurazione!) + dataClient.setTimeoutConnection(timeoutConnection); + dataClient.setConnectionsMaxTotal(connectionsMaxTotal); + dataClient.setTimeoutSocket(timeoutSocket); + // + dataClient.setConnectionsMaxPerRoute(connectionsMaxPerRoute); + dataClient.setConnectionTimeToLive(connectionTimeToLive); + // + return dataClient; + } + @Bean public CommonsDataLoaderExt dataLoader() { CommonsDataLoaderExt dataLoader = new CommonsDataLoaderExt(); + dataLoader.setCommonsDataHttpClient(dataHttpClient()); dataLoader.setProxyConfig(proxyConfig); - // NOTA timeout impostabile (da configurazione!) - dataLoader.setTimeoutConnection(timeoutConnection); - dataLoader.setConnectionsMaxTotal(connectionsMaxTotal); - dataLoader.setTimeoutSocket(timeoutSocket); - // - dataLoader.setConnectionsMaxPerRoute(connectionsMaxPerRoute); - dataLoader.setConnectionTimeToLive(connectionTimeToLive); // dataLoader.setLdapTimeoutConnection(ldapTimeoutConnection); return dataLoader; @@ -208,14 +218,8 @@ public CommonsDataLoaderExt dataLoader() { @Bean public OCSPDataLoaderExt ocspDataLoader() { OCSPDataLoaderExt ocspDataLoader = new OCSPDataLoaderExt(); + ocspDataLoader.setCommonsDataHttpClient(dataHttpClient()); ocspDataLoader.setProxyConfig(proxyConfig); - // NOTA timeout impostabile (da configurazione!) - ocspDataLoader.setTimeoutConnection(timeoutConnection); - ocspDataLoader.setConnectionsMaxTotal(connectionsMaxTotal); - ocspDataLoader.setTimeoutSocket(timeoutSocket); - // - ocspDataLoader.setConnectionsMaxPerRoute(connectionsMaxPerRoute); - // ocspDataLoader.setLdapTimeoutConnection(ldapTimeoutConnection); return ocspDataLoader; } @@ -570,7 +574,8 @@ public TLValidationJob job() { /* from 5.8 */ @Bean public CommonsDataLoader trustAllDataLoader() { - CommonsDataLoader dataLoader = new CommonsDataLoader(); + CommonsDataLoaderExt dataLoader = new CommonsDataLoaderExt(); + dataLoader.setCommonsDataHttpClient(dataHttpClient()); dataLoader.setProxyConfig(proxyConfig); dataLoader.setTrustStrategy(new TrustAllStrategy()); return dataLoader;