2 * ============LICENSE_START=======================================================
\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
13 * http://www.apache.org/licenses/LICENSE-2.0
\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
22 * ECOMP and OpenECOMP are trademarks
\r
23 * and service marks of AT&T Intellectual Property.
\r
25 package org.openecomp.restclient.rest;
\r
27 import com.sun.jersey.api.client.Client;
\r
28 import com.sun.jersey.api.client.config.ClientConfig;
\r
29 import com.sun.jersey.api.client.config.DefaultClientConfig;
\r
30 import com.sun.jersey.client.urlconnection.HTTPSProperties;
\r
32 import java.io.FileInputStream;
\r
33 import java.security.KeyStore;
\r
34 import java.security.cert.X509Certificate;
\r
36 import javax.net.ssl.HostnameVerifier;
\r
37 import javax.net.ssl.KeyManagerFactory;
\r
38 import javax.net.ssl.SSLContext;
\r
39 import javax.net.ssl.SSLSession;
\r
40 import javax.net.ssl.TrustManager;
\r
41 import javax.net.ssl.X509TrustManager;
\r
44 * This is a generic REST Client builder with flexible security validation. Sometimes it's nice to
\r
45 * be able to disable server chain cert validation and hostname validation to work-around lab
\r
46 * issues, but at the same time be able to provide complete validation with client cert + hostname +
\r
47 * server cert chain validation.
\r
48 * I used the ModelLoader REST client as a base and merged in the TSUI client I wrote which also
\r
49 * validates the server hostname and server certificate chain.
\r
54 public class RestClientBuilder {
\r
56 public static final boolean DEFAULT_VALIDATE_SERVER_HOST = false;
\r
57 public static final boolean DEFAULT_VALIDATE_CERT_CHAIN = false;
\r
58 public static final String DEFAULT_CLIENT_CERT_FILENAME = null;
\r
59 public static final String DEFAULT_CERT_PASSWORD = null;
\r
60 public static final String DEFAULT_TRUST_STORE_FILENAME = null;
\r
61 public static final int DEFAULT_CONNECT_TIMEOUT_MS = 60000;
\r
62 public static final int DEFAULT_READ_TIMEOUT_MS = 60000;
\r
64 private static final String SSL_PROTOCOL = "TLS";
\r
65 private static final String KEYSTORE_ALGORITHM = "SunX509";
\r
66 private static final String KEYSTORE_TYPE = "PKCS12";
\r
69 * TODO: implement fluent interface?
\r
72 private boolean validateServerHostname;
\r
73 private boolean validateServerCertChain;
\r
74 private String clientCertFileName;
\r
75 private String clientCertPassword;
\r
76 private String truststoreFilename;
\r
77 private int connectTimeoutInMs;
\r
78 private int readTimeoutInMs;
\r
81 * Rest Client Builder.
\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
93 public boolean isValidateServerHostname() {
\r
94 return validateServerHostname;
\r
97 public void setValidateServerHostname(boolean validateServerHostname) {
\r
98 this.validateServerHostname = validateServerHostname;
\r
101 public boolean isValidateServerCertChain() {
\r
102 return validateServerCertChain;
\r
105 public void setValidateServerCertChain(boolean validateServerCertChain) {
\r
106 this.validateServerCertChain = validateServerCertChain;
\r
109 public String getClientCertFileName() {
\r
110 return clientCertFileName;
\r
113 public void setClientCertFileName(String clientCertFileName) {
\r
114 this.clientCertFileName = clientCertFileName;
\r
117 public String getClientCertPassword() {
\r
118 return clientCertPassword;
\r
121 public void setClientCertPassword(String clientCertPassword) {
\r
122 this.clientCertPassword = clientCertPassword;
\r
125 public String getTruststoreFilename() {
\r
126 return truststoreFilename;
\r
129 public void setTruststoreFilename(String truststoreFilename) {
\r
130 this.truststoreFilename = truststoreFilename;
\r
133 public int getConnectTimeoutInMs() {
\r
134 return connectTimeoutInMs;
\r
137 public void setConnectTimeoutInMs(int connectTimeoutInMs) {
\r
138 this.connectTimeoutInMs = connectTimeoutInMs;
\r
141 public int getReadTimeoutInMs() {
\r
142 return readTimeoutInMs;
\r
145 public void setReadTimeoutInMs(int readTimeoutInMs) {
\r
146 this.readTimeoutInMs = readTimeoutInMs;
\r
152 public Client getClient() throws Exception {
\r
154 ClientConfig clientConfig = new DefaultClientConfig();
\r
156 // Check to see if we need to perform proper validation of
\r
157 // the certificate chains.
\r
158 TrustManager[] trustAllCerts = null;
\r
159 if (validateServerCertChain) {
\r
160 if (truststoreFilename != null) {
\r
161 System.setProperty("javax.net.ssl.trustStore", truststoreFilename);
\r
163 throw new IllegalArgumentException("Trust store filename must be set!");
\r
168 // We aren't validating certificates, so create a trust manager that does
\r
169 // not validate certificate chains.
\r
170 trustAllCerts = new TrustManager[] {new X509TrustManager() {
\r
171 public X509Certificate[] getAcceptedIssuers() {
\r
175 public void checkClientTrusted(X509Certificate[] certs, String authType) {}
\r
177 public void checkServerTrusted(X509Certificate[] certs, String authType) {}
\r
181 // Set up the SSL context, keystore, etc. to use for our connection
\r
183 SSLContext ctx = SSLContext.getInstance(SSL_PROTOCOL);
\r
184 KeyManagerFactory kmf = KeyManagerFactory.getInstance(KEYSTORE_ALGORITHM);
\r
185 KeyStore ks = KeyStore.getInstance(KEYSTORE_TYPE);
\r
188 if (clientCertPassword != null) {
\r
189 pwd = clientCertPassword.toCharArray();
\r
192 if (clientCertFileName != null) {
\r
193 FileInputStream fin = new FileInputStream(clientCertFileName);
\r
195 // Load the keystore and initialize the key manager factory.
\r
199 ctx.init(kmf.getKeyManagers(), trustAllCerts, null);
\r
201 ctx.init(null, trustAllCerts, null);
\r
205 // Are we performing validation of the server host name?
\r
206 if (validateServerHostname) {
\r
207 clientConfig.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,
\r
208 new HTTPSProperties(null, ctx));
\r
211 clientConfig.getProperties().put(HTTPSProperties.PROPERTY_HTTPS_PROPERTIES,
\r
212 new HTTPSProperties(new HostnameVerifier() {
\r
214 public boolean verify(String str, SSLSession sslSession) {
\r
220 // Finally, create and initialize our client...
\r
221 Client client = null;
\r
222 client = Client.create(clientConfig);
\r
223 client.setConnectTimeout(connectTimeoutInMs);
\r
224 client.setReadTimeout(readTimeoutInMs);
\r
226 // ...and return it to the caller.
\r