2 * Copyright (c) 2010-2023 Contributors to the openHAB project
4 * See the NOTICE file(s) distributed with this work for additional
7 * This program and the accompanying materials are made available under the
8 * terms of the Eclipse Public License 2.0 which is available at
9 * http://www.eclipse.org/legal/epl-2.0
11 * SPDX-License-Identifier: EPL-2.0
13 package org.openhab.binding.ihc.internal.ws.http;
15 import java.security.KeyManagementException;
16 import java.security.NoSuchAlgorithmException;
17 import java.security.SecureRandom;
18 import java.security.cert.X509Certificate;
20 import javax.net.ssl.HostnameVerifier;
21 import javax.net.ssl.SSLContext;
22 import javax.net.ssl.SSLSession;
23 import javax.net.ssl.TrustManager;
24 import javax.net.ssl.X509TrustManager;
26 import org.apache.http.client.CookieStore;
27 import org.apache.http.client.HttpClient;
28 import org.apache.http.client.protocol.HttpClientContext;
29 import org.apache.http.config.Registry;
30 import org.apache.http.config.RegistryBuilder;
31 import org.apache.http.conn.socket.ConnectionSocketFactory;
32 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
33 import org.apache.http.impl.client.BasicCookieStore;
34 import org.apache.http.impl.client.HttpClientBuilder;
35 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
36 import org.openhab.binding.ihc.internal.ws.exeptions.IhcFatalExecption;
37 import org.openhab.binding.ihc.internal.ws.exeptions.IhcTlsExecption;
38 import org.slf4j.Logger;
39 import org.slf4j.LoggerFactory;
42 * Custom HTTP connection pool, which install all-trusting trust manager.
44 * @author Pauli Anttila - Initial contribution
46 public class IhcConnectionPool {
48 private final Logger logger = LoggerFactory.getLogger(IhcConnectionPool.class);
49 private static final String DEFAULT_TLS_VER = "TLSv1";
52 * Controller TLS certificate is self signed, which means that certificate
53 * need to be manually added to java key store as a trusted certificate.
54 * This is special SSL context which will be configured to trust all
55 * certificates and manual work is not required.
57 private SSLContext sslContext;
59 /** Holds and share cookie information (session id) from authentication procedure */
60 private CookieStore cookieStore;
62 private HttpClientBuilder httpClientBuilder;
63 private HttpClientContext localContext;
64 private String tlsVersion = DEFAULT_TLS_VER;
66 public IhcConnectionPool() throws IhcFatalExecption {
67 this(DEFAULT_TLS_VER);
70 public IhcConnectionPool(String tlsVersion) throws IhcFatalExecption {
71 if (!tlsVersion.isEmpty()) {
72 this.tlsVersion = tlsVersion;
77 private void init() throws IhcFatalExecption {
80 // Create a local instance of cookie store
81 cookieStore = new BasicCookieStore();
83 // Create local HTTP context
84 localContext = HttpClientContext.create();
86 // Bind custom cookie store to the local context
87 localContext.setCookieStore(cookieStore);
89 httpClientBuilder = HttpClientBuilder.create();
91 // Setup a Trust Strategy that allows all certificates.
93 logger.debug("Initialize SSL context");
95 // Create a trust manager that does not validate certificate chains, but accept all.
96 TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() {
99 public X509Certificate[] getAcceptedIssuers() {
104 public void checkClientTrusted(X509Certificate[] certs, String authType) {
108 public void checkServerTrusted(X509Certificate[] certs, String authType) {
109 logger.trace("Trusting server cert: {}", certs[0].getIssuerDN());
113 // Install the all-trusting trust manager
115 // Old controller FW supports only SSLv3 and TLSv1, never controller TLSv1.2
116 sslContext = SSLContext.getInstance(tlsVersion);
117 logger.debug("Using TLS version {}", sslContext.getProtocol());
118 sslContext.init(null, trustAllCerts, new SecureRandom());
120 // Controller accepts only HTTPS connections and because normally IP address are used on home network rather
121 // than DNS names, create custom host name verifier.
122 HostnameVerifier hostnameVerifier = new HostnameVerifier() {
125 public boolean verify(String arg0, SSLSession arg1) {
126 logger.trace("HostnameVerifier: arg0 = {}, arg1 = {}", arg0, arg1);
131 // Create an SSL Socket Factory, to use our weakened "trust strategy"
132 SSLConnectionSocketFactory sslSocketFactory = new SSLConnectionSocketFactory(sslContext,
133 new String[] { tlsVersion }, null, hostnameVerifier);
135 Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory> create()
136 .register("https", sslSocketFactory).build();
138 // Create connection-manager using our Registry. Allows multi-threaded use
139 PoolingHttpClientConnectionManager connMngr = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
141 // Increase max connection counts
142 connMngr.setMaxTotal(20);
143 connMngr.setDefaultMaxPerRoute(6);
145 httpClientBuilder.setConnectionManager(connMngr);
146 } catch (KeyManagementException e) {
147 throw new IhcFatalExecption(e);
148 } catch (NoSuchAlgorithmException e) {
149 throw new IhcTlsExecption(e);
153 public HttpClient getHttpClient() {
154 return httpClientBuilder.build();
157 public HttpClientContext getHttpContext() {