38a855817a0df7beb8607a45c9cf54eaf5169b75
[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 boolean validateServerHostname;\r
60     private boolean validateServerCertChain;\r
61     private String clientCertFileName;\r
62     private String clientCertPassword;\r
63     private String truststoreFilename;\r
64     private int connectTimeoutInMs;\r
65     private int readTimeoutInMs;\r
66     private RestAuthenticationMode authenticationMode;\r
67     private String basicAuthUsername;\r
68     private String basicAuthPassword;\r
69     private String sslProtocol;\r
70 \r
71     /**\r
72      * Rest Client Builder.\r
73      */\r
74     public RestClientBuilder() {\r
75         validateServerHostname = DEFAULT_VALIDATE_SERVER_HOST;\r
76         validateServerCertChain = DEFAULT_VALIDATE_CERT_CHAIN;\r
77         clientCertFileName = DEFAULT_CLIENT_CERT_FILENAME;\r
78         clientCertPassword = DEFAULT_CERT_PASSWORD;\r
79         truststoreFilename = DEFAULT_TRUST_STORE_FILENAME;\r
80         connectTimeoutInMs = DEFAULT_CONNECT_TIMEOUT_MS;\r
81         readTimeoutInMs = DEFAULT_READ_TIMEOUT_MS;\r
82         authenticationMode = DEFAULT_AUTH_MODE;\r
83         basicAuthUsername = DEFAULT_BASIC_AUTH_USERNAME;\r
84         basicAuthPassword = DEFAULT_BASIC_AUTH_PASSWORD;\r
85         sslProtocol = DEFAULT_SSL_PROTOCOL;\r
86     }\r
87 \r
88     public boolean isValidateServerHostname() {\r
89         return validateServerHostname;\r
90     }\r
91 \r
92     public void setValidateServerHostname(boolean validateServerHostname) {\r
93         this.validateServerHostname = validateServerHostname;\r
94     }\r
95 \r
96     public boolean isValidateServerCertChain() {\r
97         return validateServerCertChain;\r
98     }\r
99 \r
100     public void setValidateServerCertChain(boolean validateServerCertChain) {\r
101         this.validateServerCertChain = validateServerCertChain;\r
102     }\r
103 \r
104     public String getClientCertFileName() {\r
105         return clientCertFileName;\r
106     }\r
107 \r
108     public void setClientCertFileName(String clientCertFileName) {\r
109         this.clientCertFileName = clientCertFileName;\r
110     }\r
111 \r
112     public String getClientCertPassword() {\r
113         return clientCertPassword;\r
114     }\r
115 \r
116     public void setClientCertPassword(String clientCertPassword) {\r
117         this.clientCertPassword = clientCertPassword;\r
118     }\r
119 \r
120     public String getTruststoreFilename() {\r
121         return truststoreFilename;\r
122     }\r
123 \r
124     public void setTruststoreFilename(String truststoreFilename) {\r
125         this.truststoreFilename = truststoreFilename;\r
126     }\r
127 \r
128     public int getConnectTimeoutInMs() {\r
129         return connectTimeoutInMs;\r
130     }\r
131 \r
132     public void setConnectTimeoutInMs(int connectTimeoutInMs) {\r
133         this.connectTimeoutInMs = connectTimeoutInMs;\r
134     }\r
135 \r
136     public int getReadTimeoutInMs() {\r
137         return readTimeoutInMs;\r
138     }\r
139 \r
140     public void setReadTimeoutInMs(int readTimeoutInMs) {\r
141         this.readTimeoutInMs = readTimeoutInMs;\r
142     }\r
143 \r
144     public RestAuthenticationMode getAuthenticationMode() {\r
145         return authenticationMode;\r
146     }\r
147 \r
148     public void setAuthenticationMode(RestAuthenticationMode authenticationMode) {\r
149         this.authenticationMode = authenticationMode;\r
150     }\r
151 \r
152     public String getBasicAuthUsername() {\r
153         return basicAuthUsername;\r
154     }\r
155 \r
156     public void setBasicAuthUsername(String basicAuthUsername) {\r
157         this.basicAuthUsername = basicAuthUsername;\r
158     }\r
159 \r
160     public String getBasicAuthPassword() {\r
161         return basicAuthPassword;\r
162     }\r
163 \r
164     public void setBasicAuthPassword(String basicAuthPassword) {\r
165         this.basicAuthPassword = basicAuthPassword;\r
166     }\r
167 \r
168     public String getSslProtocol() {\r
169         return sslProtocol;\r
170     }\r
171 \r
172     public void setSslProtocol(String sslProtocol) {\r
173         this.sslProtocol = sslProtocol;\r
174     }\r
175 \r
176     /**\r
177      * Returns Client configured for SSL\r
178      */\r
179     public Client getClient() throws Exception {\r
180 \r
181         switch (authenticationMode) {\r
182             case SSL_BASIC:\r
183             case SSL_CERT:\r
184                 return getClient(true);\r
185 \r
186             default:\r
187                 // return basic non-authenticating HTTP client\r
188                 return getClient(false);\r
189         }\r
190 \r
191     }\r
192 \r
193     protected void setupSecureSocketLayerClientConfig(ClientBuilder builder) throws Exception {\r
194         // Check to see if we need to perform proper validation of\r
195         // the certificate chains.\r
196         TrustManager[] trustAllCerts = null;\r
197         if (truststoreFilename != null) {\r
198             System.setProperty(TRUST_STORE_PROPERTY, truststoreFilename);\r
199         } else {\r
200             throw new IllegalArgumentException("Trust store filename must be set!");\r
201         }\r
202 \r
203         // Set up the SSL context, keystore, etc. to use for our connection\r
204         // to the AAI.\r
205         SSLContext ctx = SSLContext.getInstance(sslProtocol);\r
206         KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEYSTORE_ALGORITHM);\r
207         KeyStore ks = KeyStore.getInstance(KEYSTORE_TYPE);\r
208 \r
209         char[] pwd = null;\r
210         if (clientCertPassword != null) {\r
211             pwd = clientCertPassword.toCharArray();\r
212         }\r
213 \r
214         if (clientCertFileName != null) {\r
215             FileInputStream fin = new FileInputStream(clientCertFileName);\r
216 \r
217             // Load the keystore and initialize the key manager factory.\r
218             ks.load(fin, pwd);\r
219             kmf.init(ks, pwd);\r
220 \r
221             ctx.init(kmf.getKeyManagers(), trustAllCerts, null);\r
222         } else {\r
223             ctx.init(null, trustAllCerts, null);\r
224         }\r
225 \r
226         builder.sslContext(ctx);\r
227 \r
228         // Are we performing validation of the server host name?\r
229         if (!validateServerHostname) {\r
230             builder.hostnameVerifier((String str, SSLSession sslSession) -> true);\r
231         }\r
232     }\r
233 \r
234     /**\r
235      * Returns client instance\r
236      *\r
237      * @param useSsl - used to configure the client with an ssl-context or just plain http\r
238      */\r
239     protected Client getClient(boolean useSsl) throws Exception {\r
240 \r
241         // Finally, create and initialize our client...\r
242         ClientBuilder builder = ClientBuilder.newBuilder();\r
243         if (useSsl) {\r
244             setupSecureSocketLayerClientConfig(builder);\r
245         }\r
246         Client client = builder.build();\r
247         client.property(ClientProperties.CONNECT_TIMEOUT, connectTimeoutInMs);\r
248         client.property(ClientProperties.READ_TIMEOUT, readTimeoutInMs);\r
249 \r
250         // ...and return it to the caller.\r
251         return client;\r
252     }\r
253 \r
254     public String getBasicAuthenticationCredentials() {\r
255 \r
256         String usernameAndPassword = getBasicAuthUsername() + ":" + getBasicAuthPassword();\r
257         return "Basic " + java.util.Base64.getEncoder().encodeToString(usernameAndPassword.getBytes());\r
258     }\r
259 \r
260     /*\r
261      * Added a little bit of logic to obfuscate passwords that could be logged out (non-Javadoc)\r
262      * \r
263      * @see java.lang.Object#toString()\r
264      */\r
265     @Override\r
266     public String toString() {\r
267         return "RestClientBuilder [validateServerHostname=" + validateServerHostname + ", validateServerCertChain="\r
268                 + validateServerCertChain + ", "\r
269                 + (clientCertFileName != null ? "clientCertFileName=" + clientCertFileName + ", " : "")\r
270                 + (clientCertPassword != null\r
271                         ? "clientCertPassword="\r
272                                 + java.util.Base64.getEncoder().encodeToString(clientCertPassword.getBytes()) + ", "\r
273                         : "")\r
274                 + (truststoreFilename != null ? "truststoreFilename=" + truststoreFilename + ", " : "")\r
275                 + "connectTimeoutInMs=" + connectTimeoutInMs + ", readTimeoutInMs=" + readTimeoutInMs + ", "\r
276                 + (authenticationMode != null ? "authenticationMode=" + authenticationMode + ", " : "")\r
277                 + (basicAuthUsername != null ? "basicAuthUsername=" + basicAuthUsername + ", " : "")\r
278                 + (basicAuthPassword != null ? "basicAuthPassword="\r
279                         + java.util.Base64.getEncoder().encodeToString(basicAuthPassword.getBytes()) : "")\r
280                 + "]";\r
281     }\r
282 \r
283 }\r