Constructor inject the jakarte ee ClientBuilder
[aai/rest-client.git] / src / main / java / org / onap / aai / restclient / rest / RestClientBuilder.java
1 /**\r
2  * ============LICENSE_START=======================================================\r
3  * org.onap.aai\r
4  * ================================================================================\r
5  * Copyright © 2017-2018 AT&T Intellectual Property. All rights reserved.\r
6  * Copyright © 2017-2018 Amdocs\r
7  * ================================================================================\r
8  * Licensed under the Apache License, Version 2.0 (the "License");\r
9  * you may not use this file except in compliance with the License.\r
10  * You may obtain a copy of the License at\r
11  *\r
12  *       http://www.apache.org/licenses/LICENSE-2.0\r
13  *\r
14  * Unless required by applicable law or agreed to in writing, software\r
15  * distributed under the License is distributed on an "AS IS" BASIS,\r
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\r
17  * See the License for the specific language governing permissions and\r
18  * limitations under the License.\r
19  * ============LICENSE_END=========================================================\r
20  */\r
21 package org.onap.aai.restclient.rest;\r
22 \r
23 import java.io.FileInputStream;\r
24 import java.security.KeyStore;\r
25 import javax.net.ssl.KeyManagerFactory;\r
26 import javax.net.ssl.SSLContext;\r
27 import javax.net.ssl.SSLSession;\r
28 import javax.net.ssl.TrustManager;\r
29 import javax.ws.rs.client.Client;\r
30 import javax.ws.rs.client.ClientBuilder;\r
31 import org.glassfish.jersey.client.ClientProperties;\r
32 import org.onap.aai.restclient.enums.RestAuthenticationMode;\r
33 \r
34 /**\r
35  * This is a generic REST Client builder with flexible security validation. Sometimes it's nice to be able to disable\r
36  * server chain cert validation and hostname validation to work-around lab issues, but at the same time be able to\r
37  * provide complete validation with client cert + hostname + server cert chain validation. I used the ModelLoader REST\r
38  * client as a base and merged in the TSUI client I wrote which also validates the server hostname and server\r
39  * certificate chain.\r
40  */\r
41 public class RestClientBuilder {\r
42 \r
43     public static final boolean DEFAULT_VALIDATE_SERVER_HOST = false;\r
44     public static final boolean DEFAULT_VALIDATE_CERT_CHAIN = false;\r
45     public static final String DEFAULT_CLIENT_CERT_FILENAME = null;\r
46     public static final String DEFAULT_CERT_PASSWORD = null;\r
47     public static final String DEFAULT_TRUST_STORE_FILENAME = null;\r
48     public static final int DEFAULT_CONNECT_TIMEOUT_MS = 60000;\r
49     public static final int DEFAULT_READ_TIMEOUT_MS = 60000;\r
50     public static final RestAuthenticationMode DEFAULT_AUTH_MODE = RestAuthenticationMode.SSL_CERT;\r
51     public static final String DEFAULT_BASIC_AUTH_USERNAME = "";\r
52     public static final String DEFAULT_BASIC_AUTH_PASSWORD = "";\r
53     public static final String DEFAULT_SSL_PROTOCOL = "TLS";\r
54 \r
55     private static final String KEYSTORE_ALGORITHM = "SunX509";\r
56     private static final String KEYSTORE_TYPE = "PKCS12";\r
57     private static final String TRUST_STORE_PROPERTY = "javax.net.ssl.trustStore";\r
58 \r
59     private final ClientBuilder builder;\r
60 \r
61     private boolean validateServerHostname;\r
62     private boolean validateServerCertChain;\r
63     private String clientCertFileName;\r
64     private String clientCertPassword;\r
65     private String truststoreFilename;\r
66     private int connectTimeoutInMs;\r
67     private int readTimeoutInMs;\r
68     private RestAuthenticationMode authenticationMode;\r
69     private String basicAuthUsername;\r
70     private String basicAuthPassword;\r
71     private String sslProtocol;\r
72 \r
73     /**\r
74      * Rest Client Builder.\r
75      */\r
76     public RestClientBuilder(ClientBuilder builder) {\r
77         this.builder = builder;\r
78         validateServerHostname = DEFAULT_VALIDATE_SERVER_HOST;\r
79         validateServerCertChain = DEFAULT_VALIDATE_CERT_CHAIN;\r
80         clientCertFileName = DEFAULT_CLIENT_CERT_FILENAME;\r
81         clientCertPassword = DEFAULT_CERT_PASSWORD;\r
82         truststoreFilename = DEFAULT_TRUST_STORE_FILENAME;\r
83         connectTimeoutInMs = DEFAULT_CONNECT_TIMEOUT_MS;\r
84         readTimeoutInMs = DEFAULT_READ_TIMEOUT_MS;\r
85         authenticationMode = DEFAULT_AUTH_MODE;\r
86         basicAuthUsername = DEFAULT_BASIC_AUTH_USERNAME;\r
87         basicAuthPassword = DEFAULT_BASIC_AUTH_PASSWORD;\r
88         sslProtocol = DEFAULT_SSL_PROTOCOL;\r
89     }\r
90 \r
91     public boolean isValidateServerHostname() {\r
92         return validateServerHostname;\r
93     }\r
94 \r
95     public void setValidateServerHostname(boolean validateServerHostname) {\r
96         this.validateServerHostname = validateServerHostname;\r
97     }\r
98 \r
99     public boolean isValidateServerCertChain() {\r
100         return validateServerCertChain;\r
101     }\r
102 \r
103     public void setValidateServerCertChain(boolean validateServerCertChain) {\r
104         this.validateServerCertChain = validateServerCertChain;\r
105     }\r
106 \r
107     public String getClientCertFileName() {\r
108         return clientCertFileName;\r
109     }\r
110 \r
111     public void setClientCertFileName(String clientCertFileName) {\r
112         this.clientCertFileName = clientCertFileName;\r
113     }\r
114 \r
115     public String getClientCertPassword() {\r
116         return clientCertPassword;\r
117     }\r
118 \r
119     public void setClientCertPassword(String clientCertPassword) {\r
120         this.clientCertPassword = clientCertPassword;\r
121     }\r
122 \r
123     public String getTruststoreFilename() {\r
124         return truststoreFilename;\r
125     }\r
126 \r
127     public void setTruststoreFilename(String truststoreFilename) {\r
128         this.truststoreFilename = truststoreFilename;\r
129     }\r
130 \r
131     public int getConnectTimeoutInMs() {\r
132         return connectTimeoutInMs;\r
133     }\r
134 \r
135     public void setConnectTimeoutInMs(int connectTimeoutInMs) {\r
136         this.connectTimeoutInMs = connectTimeoutInMs;\r
137     }\r
138 \r
139     public int getReadTimeoutInMs() {\r
140         return readTimeoutInMs;\r
141     }\r
142 \r
143     public void setReadTimeoutInMs(int readTimeoutInMs) {\r
144         this.readTimeoutInMs = readTimeoutInMs;\r
145     }\r
146 \r
147     public RestAuthenticationMode getAuthenticationMode() {\r
148         return authenticationMode;\r
149     }\r
150 \r
151     public void setAuthenticationMode(RestAuthenticationMode authenticationMode) {\r
152         this.authenticationMode = authenticationMode;\r
153     }\r
154 \r
155     public String getBasicAuthUsername() {\r
156         return basicAuthUsername;\r
157     }\r
158 \r
159     public void setBasicAuthUsername(String basicAuthUsername) {\r
160         this.basicAuthUsername = basicAuthUsername;\r
161     }\r
162 \r
163     public String getBasicAuthPassword() {\r
164         return basicAuthPassword;\r
165     }\r
166 \r
167     public void setBasicAuthPassword(String basicAuthPassword) {\r
168         this.basicAuthPassword = basicAuthPassword;\r
169     }\r
170 \r
171     public String getSslProtocol() {\r
172         return sslProtocol;\r
173     }\r
174 \r
175     public void setSslProtocol(String sslProtocol) {\r
176         this.sslProtocol = sslProtocol;\r
177     }\r
178 \r
179     /**\r
180      * Returns Client configured for SSL\r
181      */\r
182     public Client getClient() throws Exception {\r
183 \r
184         switch (authenticationMode) {\r
185             case SSL_BASIC:\r
186             case SSL_CERT:\r
187                 return getClient(true);\r
188 \r
189             default:\r
190                 // return basic non-authenticating HTTP client\r
191                 return getClient(false);\r
192         }\r
193 \r
194     }\r
195 \r
196     protected void setupSecureSocketLayerClientConfig(ClientBuilder builder) throws Exception {\r
197         // Check to see if we need to perform proper validation of\r
198         // the certificate chains.\r
199         TrustManager[] trustAllCerts = null;\r
200         if (truststoreFilename != null) {\r
201             System.setProperty(TRUST_STORE_PROPERTY, truststoreFilename);\r
202         } else {\r
203             throw new IllegalArgumentException("Trust store filename must be set!");\r
204         }\r
205 \r
206         // Set up the SSL context, keystore, etc. to use for our connection\r
207         // to the AAI.\r
208         SSLContext ctx = SSLContext.getInstance(sslProtocol);\r
209         KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEYSTORE_ALGORITHM);\r
210         KeyStore ks = KeyStore.getInstance(KEYSTORE_TYPE);\r
211 \r
212         char[] pwd = null;\r
213         if (clientCertPassword != null) {\r
214             pwd = clientCertPassword.toCharArray();\r
215         }\r
216 \r
217         if (clientCertFileName != null) {\r
218             FileInputStream fin = new FileInputStream(clientCertFileName);\r
219 \r
220             // Load the keystore and initialize the key manager factory.\r
221             ks.load(fin, pwd);\r
222             kmf.init(ks, pwd);\r
223 \r
224             ctx.init(kmf.getKeyManagers(), trustAllCerts, null);\r
225         } else {\r
226             ctx.init(null, trustAllCerts, null);\r
227         }\r
228 \r
229         builder.sslContext(ctx);\r
230 \r
231         // Are we performing validation of the server host name?\r
232         if (!validateServerHostname) {\r
233             builder.hostnameVerifier((String str, SSLSession sslSession) -> true);\r
234         }\r
235     }\r
236 \r
237     /**\r
238      * Returns client instance\r
239      *\r
240      * @param useSsl - used to configure the client with an ssl-context or just plain http\r
241      */\r
242     protected Client getClient(boolean useSsl) throws Exception {\r
243 \r
244         // Finally, create and initialize our client...\r
245         \r
246         if (useSsl) {\r
247             setupSecureSocketLayerClientConfig(builder);\r
248         }\r
249         Client client = builder.build();\r
250         client.property(ClientProperties.CONNECT_TIMEOUT, connectTimeoutInMs);\r
251         client.property(ClientProperties.READ_TIMEOUT, readTimeoutInMs);\r
252 \r
253         // ...and return it to the caller.\r
254         return client;\r
255     }\r
256 \r
257     public String getBasicAuthenticationCredentials() {\r
258 \r
259         String usernameAndPassword = getBasicAuthUsername() + ":" + getBasicAuthPassword();\r
260         return "Basic " + java.util.Base64.getEncoder().encodeToString(usernameAndPassword.getBytes());\r
261     }\r
262 \r
263     /*\r
264      * Added a little bit of logic to obfuscate passwords that could be logged out (non-Javadoc)\r
265      * \r
266      * @see java.lang.Object#toString()\r
267      */\r
268     @Override\r
269     public String toString() {\r
270         return "RestClientBuilder [validateServerHostname=" + validateServerHostname + ", validateServerCertChain="\r
271                 + validateServerCertChain + ", "\r
272                 + (clientCertFileName != null ? "clientCertFileName=" + clientCertFileName + ", " : "")\r
273                 + (clientCertPassword != null\r
274                         ? "clientCertPassword="\r
275                                 + java.util.Base64.getEncoder().encodeToString(clientCertPassword.getBytes()) + ", "\r
276                         : "")\r
277                 + (truststoreFilename != null ? "truststoreFilename=" + truststoreFilename + ", " : "")\r
278                 + "connectTimeoutInMs=" + connectTimeoutInMs + ", readTimeoutInMs=" + readTimeoutInMs + ", "\r
279                 + (authenticationMode != null ? "authenticationMode=" + authenticationMode + ", " : "")\r
280                 + (basicAuthUsername != null ? "basicAuthUsername=" + basicAuthUsername + ", " : "")\r
281                 + (basicAuthPassword != null ? "basicAuthPassword="\r
282                         + java.util.Base64.getEncoder().encodeToString(basicAuthPassword.getBytes()) : "")\r
283                 + "]";\r
284     }\r
285 \r
286 }\r