Update license date and text
[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 java.security.cert.X509Certificate;\r
26 \r
27 import javax.net.ssl.HostnameVerifier;\r
28 import javax.net.ssl.KeyManagerFactory;\r
29 import javax.net.ssl.SSLContext;\r
30 import javax.net.ssl.SSLSession;\r
31 import javax.net.ssl.TrustManager;\r
32 import javax.net.ssl.X509TrustManager;\r
33 \r
34 import org.onap.aai.restclient.enums.RestAuthenticationMode;\r
35 \r
36 import com.sun.jersey.api.client.Client;\r
37 import com.sun.jersey.api.client.config.ClientConfig;\r
38 import com.sun.jersey.api.client.config.DefaultClientConfig;\r
39 import com.sun.jersey.client.urlconnection.HTTPSProperties;\r
40  \r
41 /**\r
42  * This is a generic REST Client builder with flexible security validation. Sometimes it's nice to\r
43  * be able to disable server chain cert validation and hostname validation to work-around lab\r
44  * issues, but at the same time be able to provide complete validation with client cert + hostname +\r
45  * server cert chain validation. I used the ModelLoader REST client as a base and merged in the TSUI\r
46  * client I wrote which also validates the server hostname and server certificate chain.\r
47  */\r
48 public class RestClientBuilder {\r
49 \r
50   public static final boolean DEFAULT_VALIDATE_SERVER_HOST = false;\r
51   public static final boolean DEFAULT_VALIDATE_CERT_CHAIN = false;\r
52   public static final String DEFAULT_CLIENT_CERT_FILENAME = null;\r
53   public static final String DEFAULT_CERT_PASSWORD = null;\r
54   public static final String DEFAULT_TRUST_STORE_FILENAME = null;\r
55   public static final int DEFAULT_CONNECT_TIMEOUT_MS = 60000;\r
56   public static final int DEFAULT_READ_TIMEOUT_MS = 60000;\r
57   public static final RestAuthenticationMode DEFAULT_AUTH_MODE = RestAuthenticationMode.SSL_CERT;\r
58   public static final String DEFAULT_BASIC_AUTH_USERNAME = "";\r
59   public static final String DEFAULT_BASIC_AUTH_PASSWORD = "";\r
60   public static final String DEFAULT_SSL_PROTOCOL = "TLS";\r
61 \r
62   private static final String KEYSTORE_ALGORITHM = "SunX509";\r
63   private static final String KEYSTORE_TYPE = "PKCS12";\r
64   private static final String TRUST_STORE_PROPERTY = "javax.net.ssl.trustStore";\r
65 \r
66   private boolean validateServerHostname;\r
67   private boolean validateServerCertChain;\r
68   private String clientCertFileName;\r
69   private String clientCertPassword;\r
70   private String truststoreFilename;\r
71   private int connectTimeoutInMs;\r
72   private int readTimeoutInMs;\r
73   private RestAuthenticationMode authenticationMode;\r
74   private String basicAuthUsername;\r
75   private String basicAuthPassword;\r
76   private String sslProtocol;\r
77 \r
78   /**\r
79    * Rest Client Builder.\r
80    */\r
81   public RestClientBuilder() {\r
82     validateServerHostname = DEFAULT_VALIDATE_SERVER_HOST;\r
83     validateServerCertChain = DEFAULT_VALIDATE_CERT_CHAIN;\r
84     clientCertFileName = DEFAULT_CLIENT_CERT_FILENAME;\r
85     clientCertPassword = DEFAULT_CERT_PASSWORD;\r
86     truststoreFilename = DEFAULT_TRUST_STORE_FILENAME;\r
87     connectTimeoutInMs = DEFAULT_CONNECT_TIMEOUT_MS;\r
88     readTimeoutInMs = DEFAULT_READ_TIMEOUT_MS;\r
89     authenticationMode = DEFAULT_AUTH_MODE;\r
90     basicAuthUsername = DEFAULT_BASIC_AUTH_USERNAME;\r
91     basicAuthPassword = DEFAULT_BASIC_AUTH_PASSWORD;\r
92     sslProtocol = DEFAULT_SSL_PROTOCOL;\r
93   }\r
94 \r
95   public boolean isValidateServerHostname() {\r
96     return validateServerHostname;\r
97   }\r
98 \r
99   public void setValidateServerHostname(boolean validateServerHostname) {\r
100     this.validateServerHostname = validateServerHostname;\r
101   }\r
102 \r
103   public boolean isValidateServerCertChain() {\r
104     return validateServerCertChain;\r
105   }\r
106 \r
107   public void setValidateServerCertChain(boolean validateServerCertChain) {\r
108     this.validateServerCertChain = validateServerCertChain;\r
109   }\r
110 \r
111   public String getClientCertFileName() {\r
112     return clientCertFileName;\r
113   }\r
114 \r
115   public void setClientCertFileName(String clientCertFileName) {\r
116     this.clientCertFileName = clientCertFileName;\r
117   }\r
118 \r
119   public String getClientCertPassword() {\r
120     return clientCertPassword;\r
121   }\r
122 \r
123   public void setClientCertPassword(String clientCertPassword) {\r
124     this.clientCertPassword = clientCertPassword;\r
125   }\r
126 \r
127   public String getTruststoreFilename() {\r
128     return truststoreFilename;\r
129   }\r
130 \r
131   public void setTruststoreFilename(String truststoreFilename) {\r
132     this.truststoreFilename = truststoreFilename;\r
133   }\r
134 \r
135   public int getConnectTimeoutInMs() {\r
136     return connectTimeoutInMs;\r
137   }\r
138 \r
139   public void setConnectTimeoutInMs(int connectTimeoutInMs) {\r
140     this.connectTimeoutInMs = connectTimeoutInMs;\r
141   }\r
142 \r
143   public int getReadTimeoutInMs() {\r
144     return readTimeoutInMs;\r
145   }\r
146 \r
147   public void setReadTimeoutInMs(int readTimeoutInMs) {\r
148     this.readTimeoutInMs = readTimeoutInMs;\r
149   }\r
150 \r
151   public RestAuthenticationMode getAuthenticationMode() {\r
152     return authenticationMode;\r
153   }\r
154 \r
155   public void setAuthenticationMode(RestAuthenticationMode authenticationMode) {\r
156     this.authenticationMode = authenticationMode;\r
157   }\r
158 \r
159   public String getBasicAuthUsername() {\r
160     return basicAuthUsername;\r
161   }\r
162 \r
163   public void setBasicAuthUsername(String basicAuthUsername) {\r
164     this.basicAuthUsername = basicAuthUsername;\r
165   }\r
166 \r
167   public String getBasicAuthPassword() {\r
168     return basicAuthPassword;\r
169   }\r
170 \r
171   public void setBasicAuthPassword(String basicAuthPassword) {\r
172     this.basicAuthPassword = basicAuthPassword;\r
173   }\r
174 \r
175   public String getSslProtocol() {\r
176     return sslProtocol;\r
177   }\r
178 \r
179   public void setSslProtocol(String sslProtocol) {\r
180     this.sslProtocol = sslProtocol;\r
181   }\r
182 \r
183   /**\r
184    * Returns Client configured for SSL\r
185    */\r
186   public Client getClient() throws Exception {\r
187 \r
188     switch (authenticationMode) {\r
189       case SSL_BASIC:\r
190       case SSL_CERT:\r
191         return getClient(true);\r
192 \r
193       default:\r
194         // return basic non-authenticating HTTP client\r
195         return getClient(false);\r
196     }\r
197 \r
198   }\r
199 \r
200   protected void setupSecureSocketLayerClientConfig(ClientConfig clientConfig) throws Exception {\r
201     // Check to see if we need to perform proper validation of\r
202     // the certificate chains.\r
203     TrustManager[] trustAllCerts = null;\r
204     if (validateServerCertChain) {\r
205       if (truststoreFilename != null) {\r
206         System.setProperty(TRUST_STORE_PROPERTY, truststoreFilename);\r
207       } else {\r
208         throw new IllegalArgumentException("Trust store filename must be set!");\r
209       }\r
210 \r
211     } else {\r
212 \r
213       // We aren't validating certificates, so create a trust manager that does\r
214       // not validate certificate chains.\r
215       trustAllCerts = new TrustManager[] {new X509TrustManager() {\r
216         public X509Certificate[] getAcceptedIssuers() {\r
217           return null;\r
218         }\r
219 \r
220         public void checkClientTrusted(X509Certificate[] certs, String authType) {}\r
221 \r
222         public void checkServerTrusted(X509Certificate[] certs, String authType) {}\r
223       }};\r
224     }\r
225 \r
226     // Set up the SSL context, keystore, etc. to use for our connection\r
227     // to the AAI.\r
228     SSLContext ctx = SSLContext.getInstance(sslProtocol);\r
229     KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEYSTORE_ALGORITHM);\r
230     KeyStore ks = KeyStore.getInstance(KEYSTORE_TYPE);\r
231 \r
232     char[] pwd = null;\r
233     if (clientCertPassword != null) {\r
234       pwd = clientCertPassword.toCharArray();\r
235     }\r
236 \r
237     if (clientCertFileName != null) {\r
238       FileInputStream fin = new FileInputStream(clientCertFileName);\r
239 \r
240       // Load the keystore and initialize the key manager factory.\r
241       ks.load(fin, pwd);\r
242       kmf.init(ks, pwd);\r
243 \r
244       ctx.init(kmf.getKeyManagers(), trustAllCerts, null);\r
245     } else {\r
246       ctx.init(null, trustAllCerts, null);\r
247     }\r
248 \r
249     // Are we performing validation of the server host name?\r
250     if (validateServerHostname) {\r
251       clientConfig.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,\r
252           new HTTPSProperties(null, ctx));\r
253 \r
254     } else {\r
255       clientConfig.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,\r
256           new HTTPSProperties(new HostnameVerifier() {\r
257             @Override\r
258             public boolean verify(String str, SSLSession sslSession) {\r
259               return true;\r
260             }\r
261           }, ctx));\r
262     }\r
263   }\r
264 \r
265 \r
266   /**\r
267    * Returns client instance\r
268    * \r
269    * @param useSsl - used to configure the client with an ssl-context or just plain http\r
270    */\r
271   protected Client getClient(boolean useSsl) throws Exception {\r
272 \r
273     ClientConfig clientConfig = new DefaultClientConfig();\r
274 \r
275     if (useSsl) {\r
276       setupSecureSocketLayerClientConfig(clientConfig);\r
277     }\r
278 \r
279     // Finally, create and initialize our client...\r
280     Client client = null;\r
281     client = Client.create(clientConfig);\r
282     client.setConnectTimeout(connectTimeoutInMs);\r
283     client.setReadTimeout(readTimeoutInMs);\r
284 \r
285     // ...and return it to the caller.\r
286     return client;\r
287   }\r
288 \r
289   public String getBasicAuthenticationCredentials() {\r
290 \r
291     String usernameAndPassword = getBasicAuthUsername() + ":" + getBasicAuthPassword();\r
292     return "Basic " + java.util.Base64.getEncoder().encodeToString(usernameAndPassword.getBytes());\r
293   }\r
294 \r
295   /* \r
296    * Added a little bit of logic to obfuscate passwords that could be logged out\r
297    * (non-Javadoc)\r
298    * @see java.lang.Object#toString()\r
299    */\r
300   @Override\r
301   public String toString() {\r
302     return "RestClientBuilder [validateServerHostname=" + validateServerHostname\r
303         + ", validateServerCertChain=" + validateServerCertChain + ", "\r
304         + (clientCertFileName != null ? "clientCertFileName=" + clientCertFileName + ", " : "")\r
305         + (clientCertPassword != null\r
306             ? "clientCertPassword="\r
307                 + java.util.Base64.getEncoder().encodeToString(clientCertPassword.getBytes()) + ", "\r
308             : "")\r
309         + (truststoreFilename != null ? "truststoreFilename=" + truststoreFilename + ", " : "")\r
310         + "connectTimeoutInMs=" + connectTimeoutInMs + ", readTimeoutInMs=" + readTimeoutInMs + ", "\r
311         + (authenticationMode != null ? "authenticationMode=" + authenticationMode + ", " : "")\r
312         + (basicAuthUsername != null ? "basicAuthUsername=" + basicAuthUsername + ", " : "")\r
313         + (basicAuthPassword != null ? "basicAuthPassword="\r
314             + java.util.Base64.getEncoder().encodeToString(basicAuthPassword.getBytes()) : "")\r
315         + "]";\r
316   }\r
317 \r
318 }\r