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