ansible adapter changes for multiple ansible servs
[appc.git] / appc-adapters / appc-ansible-adapter / appc-ansible-adapter-bundle / src / main / java / org / onap / appc / adapter / ansible / impl / ConnectionBuilder.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * ONAP : APPC
4  * ================================================================================
5  * Copyright (C) 2018-2019 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Copyright (C) 2017 Amdocs
8  * ================================================================================
9  * Modifications Copyright © 2018 IBM.
10  * =============================================================================
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  *      http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  *
23  * ============LICENSE_END=========================================================
24  */
25
26 package org.onap.appc.adapter.ansible.impl;
27
28 import java.io.Closeable;
29 import java.io.FileInputStream;
30 import java.io.IOException;
31 import java.security.KeyManagementException;
32 import java.security.KeyStore;
33 import java.security.KeyStoreException;
34 import java.security.NoSuchAlgorithmException;
35 import java.security.cert.CertificateException;
36 import java.security.cert.CertificateFactory;
37 import java.security.cert.X509Certificate;
38 import javax.net.ssl.SSLContext;
39 import org.apache.http.HttpEntity;
40 import org.apache.http.HttpResponse;
41 import org.apache.http.auth.AuthScope;
42 import org.apache.http.auth.UsernamePasswordCredentials;
43 import org.apache.http.client.config.RequestConfig;
44 import org.apache.http.client.methods.HttpGet;
45 import org.apache.http.client.methods.HttpPost;
46 import org.apache.http.client.protocol.HttpClientContext;
47 import org.apache.http.conn.ssl.NoopHostnameVerifier;
48 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
49 import org.apache.http.conn.ssl.SSLContexts;
50 import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
51 import org.apache.http.entity.StringEntity;
52 import org.apache.http.impl.client.BasicCredentialsProvider;
53 import org.apache.http.impl.client.CloseableHttpClient;
54 import org.apache.http.impl.client.HttpClients;
55 import org.apache.http.util.EntityUtils;
56 import org.onap.appc.adapter.ansible.model.AnsibleResult;
57 import org.onap.appc.adapter.ansible.model.AnsibleResultCodes;
58 import com.att.eelf.configuration.EELFLogger;
59 import com.att.eelf.configuration.EELFManager;
60 import org.json.JSONObject;
61 import javax.net.ssl.SSLException;
62 import org.onap.appc.exceptions.APPCException;
63 import org.apache.commons.lang.StringUtils;
64
65 /**
66  * Returns a custom http client - based on options - can create one with ssl
67  * using an X509 certificate that does NOT have a known CA - create one which
68  * trusts ALL SSL certificates - return default httpclient (which only trusts
69  * known CAs from default cacerts file for process) this is the default option
70  **/
71
72 public class ConnectionBuilder implements Closeable {
73     private static final String STATUS_CODE_KEY = "StatusCode";
74     private static final EELFLogger logger = EELFManager.getInstance().getLogger(ConnectionBuilder.class);
75
76     private CloseableHttpClient httpClient = null;
77     private HttpClientContext httpContext = new HttpClientContext();
78
79     /**
80      * Constructor that initializes an http client based on certificate
81      **/
82
83
84     public ConnectionBuilder(String certFile, int timeout) throws KeyStoreException, CertificateException, IOException,
85             KeyManagementException, NoSuchAlgorithmException{
86
87         /* Point to the certificate */
88         try(FileInputStream fs = new FileInputStream(certFile)) {
89
90             /* Generate a certificate from the X509 */
91             CertificateFactory cf = CertificateFactory.getInstance("X.509");
92             X509Certificate cert = (X509Certificate) cf.generateCertificate(fs);
93
94             /* Create a keystore object and load the certificate there */
95             KeyStore keystore = KeyStore.getInstance(KeyStore.getDefaultType());
96             keystore.load(null, null);
97             keystore.setCertificateEntry("cacert", cert);
98
99             SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(keystore).build();
100             SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext,
101                     SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
102
103             RequestConfig config = RequestConfig.custom().setSocketTimeout(timeout).build();
104             httpClient = HttpClients.custom().setDefaultRequestConfig(config).setSSLSocketFactory(factory).build();
105         }
106     }
107
108     /**
109      * Constructor which trusts all certificates in a specific java keystore file
110      * (assumes a JKS file)
111      **/
112     public ConnectionBuilder(String trustStoreFile, char[] trustStorePasswd, int timeout, String serverIP)
113             throws KeyStoreException, IOException, KeyManagementException, NoSuchAlgorithmException,
114             CertificateException ,APPCException{
115
116         /* Load the specified trustStore */
117         KeyStore keystore = KeyStore.getInstance("JKS");
118         FileInputStream readStream = new FileInputStream(trustStoreFile);
119         keystore.load(readStream, trustStorePasswd);
120         if (StringUtils.isNotBlank(serverIP)) {
121             SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
122             SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext, new NoopHostnameVerifier());
123
124             RequestConfig config = RequestConfig.custom().setSocketTimeout(timeout).build();
125             httpClient = HttpClients.custom().setDefaultRequestConfig(config).setSSLSocketFactory(factory).build();
126         } else {
127             SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(keystore).build();
128             SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext,
129                     SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
130             RequestConfig config = RequestConfig.custom().setSocketTimeout(timeout).build();
131             httpClient = HttpClients.custom().setDefaultRequestConfig(config).setSSLSocketFactory(factory).build();
132         }
133
134     }
135
136     /**
137      * Constructor that trusts ALL SSl certificates (NOTE : ONLY FOR DEV TESTING) if
138      * Mode == 1 or Default if Mode == 0
139      */
140
141     public ConnectionBuilder(int mode, int timeout)
142             throws SSLException, NoSuchAlgorithmException, KeyStoreException, KeyManagementException,APPCException{
143         RequestConfig config = RequestConfig.custom().setSocketTimeout(timeout).build();
144         if (mode == 1) {
145             SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
146             SSLConnectionSocketFactory factory = new SSLConnectionSocketFactory(sslcontext,
147                     SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
148
149             httpClient = HttpClients.custom().setDefaultRequestConfig(config).setSSLSocketFactory(factory).build();
150         } else {
151             httpClient = HttpClients.custom().setDefaultRequestConfig(config).build();
152         }
153     }
154
155     // Use to create an http context with auth headers
156     public void setHttpContext(String user, String myPassword) {
157
158         // Are credential provided ? If so, set the context to be used
159         if (user != null && !user.isEmpty() && myPassword != null && !myPassword.isEmpty()) {
160             UsernamePasswordCredentials credentials = new UsernamePasswordCredentials(user, myPassword);
161             AuthScope authscope = new AuthScope(AuthScope.ANY_HOST, AuthScope.ANY_PORT);
162             BasicCredentialsProvider credsprovider = new BasicCredentialsProvider();
163             credsprovider.setCredentials(authscope, credentials);
164             httpContext.setCredentialsProvider(credsprovider);
165         }
166     }
167
168     // Method posts to the ansible server and writes out response to
169     // Ansible result object
170     public AnsibleResult post(String agentUrl, String payload) {
171
172         AnsibleResult result = new AnsibleResult();
173         try {
174
175             HttpPost postObj = new HttpPost(agentUrl);
176             StringEntity bodyParams = new StringEntity(payload, "UTF-8");
177             postObj.setEntity(bodyParams);
178             postObj.addHeader("Content-type", "application/json");
179
180             HttpResponse response = httpClient.execute(postObj, httpContext);
181
182             HttpEntity entity = response.getEntity();
183             String responseOutput = entity != null ? EntityUtils.toString(entity) : null;
184             int responseCode = response.getStatusLine().getStatusCode();
185             result.setStatusCode(responseCode);
186             result.setStatusMessage(responseOutput);
187         } catch (IOException io) {
188             logger.error("Caught IOException", io);
189             result.setStatusCode(AnsibleResultCodes.IO_EXCEPTION.getValue());
190             result.setStatusMessage(io.getMessage());
191         }
192         return result;
193     }
194
195     // Method gets information from an Ansible server and writes out response to
196     // Ansible result object
197
198     public AnsibleResult get(String agentUrl) {
199
200         AnsibleResult result = new AnsibleResult();
201
202         try {
203             HttpGet getObj = new HttpGet(agentUrl);
204             HttpResponse response = httpClient.execute(getObj, httpContext);
205
206             HttpEntity entity = response.getEntity();
207             String responseOutput = entity != null ? EntityUtils.toString(entity) : null;
208             int responseCode = response.getStatusLine().getStatusCode();
209             logger.info("GetResult response for ansible GET URL" + agentUrl + " returned " + responseOutput);
210             JSONObject postResponse = new JSONObject(responseOutput);
211             if (postResponse.has(STATUS_CODE_KEY)) {
212                 int codeStatus = postResponse.getInt(STATUS_CODE_KEY);
213                 if (codeStatus == AnsibleResultCodes.PENDING.getValue())
214                     result.setStatusCode(codeStatus);
215                 else
216                     result.setStatusCode(responseCode);
217             } else
218                 result.setStatusCode(responseCode);
219             result.setStatusMessage(responseOutput);
220         } catch (IOException io) {
221             result.setStatusCode(AnsibleResultCodes.IO_EXCEPTION.getValue());
222             result.setStatusMessage(io.getMessage());
223             logger.error("Caught IOException", io);
224         }
225         return result;
226     }
227
228     @Override
229     public void close() {
230         if (httpClient != null) {
231             try {
232                 httpClient.close();
233             } catch (IOException e) {
234                 logger.error("Caught IOException during httpClient close", e);
235             }
236         }
237     }
238
239 }