2 * ============LICENSE_START======================================================================
3 * Copyright (C) 2021 Nokia. All rights reserved.
4 * ===============================================================================================
5 * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except
6 * in compliance with the License. You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software distributed under the License
11 * is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
12 * or implied. See the License for the specific language governing permissions and limitations under
14 * ============LICENSE_END========================================================================
16 package org.oran.datafile.http;
19 import java.io.IOException;
20 import java.io.InputStream;
21 import java.nio.file.Files;
22 import java.nio.file.Paths;
23 import java.security.KeyStore;
24 import java.security.KeyStoreException;
25 import java.security.NoSuchAlgorithmException;
26 import java.security.UnrecoverableKeyException;
27 import java.security.cert.CertificateException;
29 import javax.net.ssl.HostnameVerifier;
30 import javax.net.ssl.SSLContext;
32 import org.apache.http.config.Registry;
33 import org.apache.http.config.RegistryBuilder;
34 import org.apache.http.conn.socket.ConnectionSocketFactory;
35 import org.apache.http.conn.ssl.DefaultHostnameVerifier;
36 import org.apache.http.conn.ssl.NoopHostnameVerifier;
37 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
38 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
39 import org.apache.http.ssl.SSLContextBuilder;
40 import org.apache.http.ssl.SSLContexts;
41 import org.oran.datafile.exceptions.DatafileTaskException;
42 import org.slf4j.Logger;
43 import org.slf4j.LoggerFactory;
44 import org.springframework.core.io.FileSystemResource;
47 * Utility class supplying connection manager for HTTPS protocol.
50 public class HttpsClientConnectionManagerUtil {
52 private HttpsClientConnectionManagerUtil() {
55 private static final Logger logger = LoggerFactory.getLogger(HttpsClientConnectionManagerUtil.class);
56 // Be aware to be less than ScheduledTasks.NUMBER_OF_WORKER_THREADS
57 private static final int MAX_NUMBER_OF_CONNECTIONS = 200;
58 private static PoolingHttpClientConnectionManager connectionManager;
60 public static PoolingHttpClientConnectionManager instance() throws DatafileTaskException {
61 if (connectionManager == null) {
62 throw new DatafileTaskException("ConnectionManager has to be set or update first");
64 return connectionManager;
67 public static void setupOrUpdate(String keyCertPath, String keyCertPasswordPath, String trustedCaPath,
68 String trustedCaPasswordPath, boolean useHostnameVerifier) throws DatafileTaskException {
69 synchronized (HttpsClientConnectionManagerUtil.class) {
70 if (connectionManager != null) {
71 connectionManager.close();
72 connectionManager = null;
74 setup(keyCertPath, keyCertPasswordPath, trustedCaPath, trustedCaPasswordPath, useHostnameVerifier);
76 logger.trace("HttpsConnectionManager setup or updated");
79 private static void setup(String keyCertPath, String keyCertPasswordPath, String trustedCaPath,
80 String trustedCaPasswordPath, boolean useHostnameVerifier) throws DatafileTaskException {
82 SSLContextBuilder sslBuilder = SSLContexts.custom();
83 sslBuilder = supplyKeyInfo(keyCertPath, keyCertPasswordPath, sslBuilder);
84 if (!trustedCaPath.isEmpty()) {
85 sslBuilder = supplyTrustInfo(trustedCaPath, trustedCaPasswordPath, sslBuilder);
88 SSLContext sslContext = sslBuilder.build();
90 HostnameVerifier hostnameVerifier =
91 useHostnameVerifier ? new DefaultHostnameVerifier() : NoopHostnameVerifier.INSTANCE;
93 SSLConnectionSocketFactory sslConnectionSocketFactory =
94 new SSLConnectionSocketFactory(sslContext, new String[] {"TLSv1.2"}, null, hostnameVerifier);
96 Registry<ConnectionSocketFactory> socketFactoryRegistry =
97 RegistryBuilder.<ConnectionSocketFactory>create().register("https", sslConnectionSocketFactory).build();
99 connectionManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
100 connectionManager.setMaxTotal(MAX_NUMBER_OF_CONNECTIONS);
102 } catch (Exception e) {
103 throw new DatafileTaskException("Unable to prepare HttpsConnectionManager : ", e);
107 private static SSLContextBuilder supplyKeyInfo(String keyCertPath, String keyCertPasswordPath,
108 SSLContextBuilder sslBuilder) throws IOException, KeyStoreException, NoSuchAlgorithmException,
109 CertificateException, UnrecoverableKeyException {
110 String keyPass = Files.readString(Paths.get((keyCertPasswordPath)));
111 KeyStore keyFile = createKeyStore(keyCertPath, keyPass);
112 return sslBuilder.loadKeyMaterial(keyFile, keyPass.toCharArray());
115 private static KeyStore createKeyStore(String path, String storePassword)
116 throws IOException, KeyStoreException, NoSuchAlgorithmException, CertificateException {
117 logger.trace("Creating manager from file: {}", path);
118 try (InputStream fis = createInputStream(path)) {
119 KeyStore keyStore = KeyStore.getInstance("PKCS12");
120 keyStore.load(fis, storePassword.toCharArray());
125 private static InputStream createInputStream(String localFileName) throws IOException {
126 FileSystemResource realResource = new FileSystemResource(Paths.get(localFileName));
127 return realResource.getInputStream();
130 private static SSLContextBuilder supplyTrustInfo(String trustedCaPath, String trustedCaPasswordPath,
131 SSLContextBuilder sslBuilder)
132 throws NoSuchAlgorithmException, KeyStoreException, CertificateException, IOException {
133 String trustPass = Files.readString(Paths.get((trustedCaPasswordPath)));
134 File trustStoreFile = new File(trustedCaPath);
135 return sslBuilder.loadTrustMaterial(trustStoreFile, trustPass.toCharArray());