Removing jackson to mitigate cve-2017-4995
[vfc/nfvo/driver/vnfm/svnfm.git] / nokiav2 / driver / src / test / java / org / onap / vfc / nfvo / driver / vnfm / svnfm / nokia / vnfm / TestGenericSecurityProvider.java
1 /*
2  * Copyright 2016-2017, Nokia Corporation
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package org.onap.vfc.nfvo.driver.vnfm.svnfm.nokia.vnfm;
18
19 import com.google.gson.Gson;
20 import com.google.gson.JsonParseException;
21 import com.google.gson.annotations.SerializedName;
22 import com.nokia.cbam.lcn.v32.JSON;
23 import io.reactivex.Observable;
24 import java.io.IOException;
25 import java.lang.annotation.Annotation;
26 import java.lang.reflect.Type;
27 import java.nio.file.Files;
28 import java.nio.file.Path;
29 import java.nio.file.Paths;
30 import java.util.Base64;
31 import javax.xml.bind.annotation.XmlAccessType;
32 import javax.xml.bind.annotation.XmlAccessorType;
33 import javax.xml.bind.annotation.XmlElement;
34 import javax.xml.bind.annotation.XmlRootElement;
35 import okhttp3.OkHttpClient;
36 import okhttp3.RequestBody;
37 import okhttp3.ResponseBody;
38 import org.junit.After;
39 import org.junit.Before;
40 import org.junit.Test;
41 import retrofit2.Converter;
42 import retrofit2.Retrofit;
43 import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
44 import retrofit2.converter.gson.GsonConverterFactory;
45 import retrofit2.http.GET;
46 import retrofit2.http.Headers;
47
48 import static junit.framework.TestCase.*;
49 import static org.springframework.test.util.ReflectionTestUtils.setField;
50
51 interface TestService {
52     @Headers({
53             "Content-Type:application/json"
54     })
55     @GET("subscriptions")
56     Observable<TestResource> subscriptionsGet();
57 }
58
59 @XmlRootElement(name = "Subscription")
60 @XmlAccessorType(XmlAccessType.FIELD)
61 class TestResource {
62     @XmlElement(name = "id")
63     @SerializedName("id")
64     public String id = null;
65 }
66
67 class GsonCustomConverterFactory extends Converter.Factory {
68     private final Gson gson;
69     private final GsonConverterFactory gsonConverterFactory;
70
71     private GsonCustomConverterFactory(Gson gson) {
72         if (gson == null)
73             throw new NullPointerException("gson == null");
74         this.gson = gson;
75         this.gsonConverterFactory = GsonConverterFactory.create(gson);
76     }
77
78     public static GsonCustomConverterFactory create(Gson gson) {
79         return new GsonCustomConverterFactory(gson);
80     }
81
82     @Override
83     public Converter<ResponseBody, ?> responseBodyConverter(Type type, Annotation[] annotations, Retrofit retrofit) {
84         if (type.equals(String.class))
85             return new GsonResponseBodyConverterToString<Object>(gson, type);
86         else
87             return gsonConverterFactory.responseBodyConverter(type, annotations, retrofit);
88     }
89
90     @Override
91     public Converter<?, RequestBody> requestBodyConverter(Type type, Annotation[] parameterAnnotations, Annotation[] methodAnnotations, Retrofit retrofit) {
92         return gsonConverterFactory.requestBodyConverter(type, parameterAnnotations, methodAnnotations, retrofit);
93     }
94 }
95
96 class GsonResponseBodyConverterToString<T> implements Converter<ResponseBody, T> {
97     private final Gson gson;
98     private final Type type;
99
100     GsonResponseBodyConverterToString(Gson gson, Type type) {
101         this.gson = gson;
102         this.type = type;
103     }
104
105     @Override
106     public T convert(ResponseBody value) throws IOException {
107         String returned = value.string();
108         try {
109             return gson.fromJson(returned, type);
110         } catch (JsonParseException e) {
111             return (T) returned;
112         }
113     }
114 }
115
116 public class TestGenericSecurityProvider extends TestBase {
117     GenericSecurityProvider securityProvider = new CbamSecurityProvider() {
118     };
119
120     HttpTestServer testServer = new HttpTestServer();
121     String url;
122
123     @Before
124     public void init() throws Exception {
125         setField(securityProvider, "skipCertificateVerification", true);
126         setField(securityProvider, "skipHostnameVerification", true);
127         testServer = new HttpTestServer();
128         testServer.start();
129         url = testServer._server.getURI().toString();
130     }
131
132     @After
133     public void testServer() throws Exception {
134         testServer.stop();
135     }
136
137     /**
138      * test skipping certificate and skipping hostname verification
139      */
140     @Test
141     public void testSkipHostAndSkipCertifiacateVerification() throws Exception {
142         setField(securityProvider, "skipCertificateVerification", true);
143         setField(securityProvider, "skipHostnameVerification", true);
144         //when
145         TestResource testResource = fireRequest();
146         //verify
147         assertEquals("1234", testResource.id);
148         //when
149         securityProvider.buildTrustManager().checkClientTrusted(null, null);
150         //verify
151         //no security exception is thrown
152     }
153
154     /**
155      * test skipping certificate and doing hostname verification
156      */
157     @Test
158     public void testHostAndSkipCertifiacateVerification() throws Exception {
159         setField(securityProvider, "skipCertificateVerification", true);
160         setField(securityProvider, "skipHostnameVerification", false);
161         url = url.replace("127.0.0.1", "localhost");
162         TestResource testResource = fireRequest();
163         assertEquals("1234", testResource.id);
164     }
165
166     /**
167      * test skipping certificate and doing hostname verification
168      * (if hostname is invalid exception is propagated)
169      */
170     @Test
171     public void testHostAndSkipCertifiacateVerificationNegativeCase() throws Exception {
172         setField(securityProvider, "skipCertificateVerification", true);
173         setField(securityProvider, "skipHostnameVerification", false);
174         //url = url.replace("127.0.0.1", "localhost");
175         try {
176             fireRequest();
177             fail();
178         } catch (Exception e) {
179             assertEquals(javax.net.ssl.SSLPeerUnverifiedException.class, e.getCause().getClass());
180             assertTrue(e.getCause().getMessage().contains("Hostname 127.0.0.1 not verified"));
181         }
182     }
183
184     /**
185      * test certificate and hostname verification
186      */
187     @Test
188     public void testHostAndCertifiacateVerification() throws Exception {
189         Path jksPath = Paths.get(TestCbamTokenProvider.class.getResource("/unittests/localhost.cert.pem").toURI());
190         String cert = Base64.getEncoder().encodeToString(Files.readAllBytes(jksPath));
191         setField(securityProvider, "trustedCertificates", cert);
192         setField(securityProvider, "skipCertificateVerification", false);
193         setField(securityProvider, "skipHostnameVerification", false);
194         url = url.replace("127.0.0.1", "localhost");
195         TestResource testResource = fireRequest();
196         assertEquals("1234", testResource.id);
197     }
198
199     /**
200      * test certificate and hostname verification
201      * (not trusted certificate)
202      */
203     @Test
204     public void testHostAndCertifiacateVerificationNegative() throws Exception {
205         Path jksPath = Paths.get(TestCbamTokenProvider.class.getResource("/unittests/sample.cert.pem").toURI());
206         String cert = Base64.getEncoder().encodeToString(Files.readAllBytes(jksPath));
207         setField(securityProvider, "trustedCertificates", cert);
208         setField(securityProvider, "skipCertificateVerification", false);
209         setField(securityProvider, "skipHostnameVerification", false);
210         url = url.replace("127.0.0.1", "localhost");
211         try {
212             fireRequest();
213             fail();
214         } catch (Exception e) {
215             assertEquals(javax.net.ssl.SSLHandshakeException.class, e.getCause().getClass());
216             assertTrue(e.getCause().getMessage().contains("unable to find valid certification path to requested target"));
217         }
218     }
219
220     /**
221      * test certificate and hostname verification
222      */
223     @Test
224     public void testSkipHostAndCertifiacateVerification() throws Exception {
225         Path jksPath = Paths.get(TestCbamTokenProvider.class.getResource("/unittests/localhost.cert.pem").toURI());
226         String cert = Base64.getEncoder().encodeToString(Files.readAllBytes(jksPath));
227         setField(securityProvider, "trustedCertificates", cert);
228         setField(securityProvider, "skipCertificateVerification", false);
229         setField(securityProvider, "skipHostnameVerification", true);
230         //url = url.replace("127.0.0.1", "localhost");
231         TestResource testResource = fireRequest();
232         assertEquals("1234", testResource.id);
233     }
234
235     /**
236      * empty trusted pem results in error if verification is required
237      */
238     @Test
239     public void testEmptyTrustStoreWhenCheckingIsRequired() throws Exception {
240         setField(securityProvider, "trustedCertificates", "");
241         setField(securityProvider, "skipCertificateVerification", false);
242         try {
243             securityProvider.buildTrustManager();
244             fail();
245         } catch (Exception e) {
246             assertEquals("If the skipCertificateVerification is set to false (default) the trustedCertificates can not be empty", e.getMessage());
247         }
248     }
249
250     /**
251      * invalid PEM results in fast fail error
252      */
253     @Test
254     public void testInvalidPem() throws Exception {
255         setField(securityProvider, "trustedCertificates", "______");
256         setField(securityProvider, "skipCertificateVerification", false);
257         try {
258             securityProvider.buildTrustManager();
259             fail();
260         } catch (Exception e) {
261             assertEquals("The trustedCertificates must be a base64 encoded collection of PEM certificates", e.getMessage());
262         }
263     }
264
265     /**
266      * invalid PEM results in fast fail error
267      */
268     @Test
269     public void testEmptyInvalidPem() throws Exception {
270         setField(securityProvider, "trustedCertificates", "a3VrdQo=");
271         setField(securityProvider, "skipCertificateVerification", false);
272         try {
273             securityProvider.buildTrustManager();
274             fail();
275         } catch (Exception e) {
276             assertEquals("No certificate can be extracted from kuku\n", e.getMessage());
277         }
278     }
279
280     /**
281      * bad certificate content results in fast fail error
282      */
283     @Test
284     public void testEmptyInvalidPemContent() throws Exception {
285         String badCert = "-----BEGIN CERTIFICATE-----\nXXXXXX\n-----END CERTIFICATE-----";
286         setField(securityProvider, "trustedCertificates", Base64.getEncoder().encodeToString(badCert.getBytes()));
287         setField(securityProvider, "skipCertificateVerification", false);
288         try {
289             securityProvider.buildTrustManager();
290             fail();
291         } catch (Exception e) {
292             assertEquals("Unable to create keystore", e.getMessage());
293         }
294     }
295
296     /**
297      * bad certificate content results in fast fail error for SSL socket factory
298      */
299     @Test
300     public void testEmptyInvalidPemContentSSl() throws Exception {
301         String badCert = "-----BEGIN CERTIFICATE-----\nXXXXXX\n-----END CERTIFICATE-----";
302         setField(securityProvider, "trustedCertificates", Base64.getEncoder().encodeToString(badCert.getBytes()));
303         setField(securityProvider, "skipCertificateVerification", false);
304         try {
305             securityProvider.buildSSLSocketFactory();
306             fail();
307         } catch (Exception e) {
308             assertEquals("Unable to create SSL socket factory", e.getMessage());
309         }
310     }
311
312     private TestResource fireRequest() {
313         OkHttpClient client =
314                 new OkHttpClient.Builder()
315                         .sslSocketFactory(securityProvider.buildSSLSocketFactory(), securityProvider.buildTrustManager())
316                         .hostnameVerifier(securityProvider.buildHostnameVerifier()).build();
317         TestService test1 = new Retrofit.Builder().baseUrl(url).client(client)
318                 .addConverterFactory(GsonCustomConverterFactory.create(new JSON().getGson()))
319                 .addCallAdapterFactory(RxJava2CallAdapterFactory.create()).build().create(TestService.class);
320         testServer.respones.add("{ \"id\" : \"1234\" } ");
321         testServer.codes.add(200);
322         TestService test = test1;
323         return test.subscriptionsGet().blockingFirst();
324     }
325
326 }