Revert "Support SIP TLS"
[sdc.git] / utils / webseal-simulator / src / main / java / org / openecomp / sdc / webseal / simulator / SdcProxy.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2019 AT&T Intellectual Property. All rights reserved.
6  * ================================================================================
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  * ============LICENSE_END=========================================================
19  */
20
21 package org.openecomp.sdc.webseal.simulator;
22
23 import static java.nio.charset.StandardCharsets.UTF_8;
24
25 import java.io.IOException;
26 import java.io.InputStream;
27 import java.io.OutputStream;
28 import java.net.MalformedURLException;
29 import java.net.URL;
30 import java.net.URLEncoder;
31 import java.security.KeyStoreException;
32 import java.security.NoSuchAlgorithmException;
33 import java.util.ArrayList;
34 import java.util.Arrays;
35 import java.util.Enumeration;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.Map.Entry;
39 import java.util.Set;
40 import java.util.stream.Collectors;
41 import java.util.zip.GZIPInputStream;
42 import javax.net.ssl.SSLContext;
43 import javax.servlet.RequestDispatcher;
44 import javax.servlet.ServletConfig;
45 import javax.servlet.ServletException;
46 import javax.servlet.ServletInputStream;
47 import javax.servlet.http.Cookie;
48 import javax.servlet.http.HttpServlet;
49 import javax.servlet.http.HttpServletRequest;
50 import javax.servlet.http.HttpServletResponse;
51 import lombok.AllArgsConstructor;
52 import lombok.Getter;
53 import org.apache.commons.lang3.StringUtils;
54 import org.apache.http.Header;
55 import org.apache.http.HttpHeaders;
56 import org.apache.http.HttpStatus;
57 import org.apache.http.client.methods.CloseableHttpResponse;
58 import org.apache.http.client.methods.HttpDelete;
59 import org.apache.http.client.methods.HttpGet;
60 import org.apache.http.client.methods.HttpPost;
61 import org.apache.http.client.methods.HttpPut;
62 import org.apache.http.client.methods.HttpRequestBase;
63 import org.apache.http.client.methods.HttpUriRequest;
64 import org.apache.http.config.Registry;
65 import org.apache.http.config.RegistryBuilder;
66 import org.apache.http.conn.socket.ConnectionSocketFactory;
67 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
68 import org.apache.http.conn.ssl.NoopHostnameVerifier;
69 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
70 import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
71 import org.apache.http.entity.ContentType;
72 import org.apache.http.entity.InputStreamEntity;
73 import org.apache.http.impl.client.CloseableHttpClient;
74 import org.apache.http.impl.client.HttpClients;
75 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
76 import org.apache.http.ssl.SSLContextBuilder;
77 import org.openecomp.sdc.webseal.simulator.conf.Conf;
78 import org.slf4j.Logger;
79 import org.slf4j.LoggerFactory;
80
81 public class SdcProxy extends HttpServlet {
82
83     private static final Logger LOGGER = LoggerFactory.getLogger(SdcProxy.class);
84
85     private static final long serialVersionUID = 1L;
86     private static final Set<String> RESERVED_HEADERS =
87         Arrays.stream(ReservedHeaders.values()).map(ReservedHeaders::getValue).collect(Collectors.toSet());
88     private static final String USER_ID = "USER_ID";
89     private static final String HTTP_IV_USER = "HTTP_IV_USER";
90     private static final String SDC1 = "/sdc1";
91     private static final String ONBOARDING = "/onboarding/";
92     private static final String SCRIPTS = "/scripts";
93     private static final String STYLES = "/styles";
94     private static final String LANGUAGES = "/languages";
95     private static final String CONFIGURATIONS = "/configurations";
96     private URL url;
97     private CloseableHttpClient httpClient;
98     private Conf conf;
99
100     @Override
101     public void init(ServletConfig config) throws ServletException {
102         super.init(config);
103         conf = Conf.getInstance();
104         try {
105             url = new URL(conf.getFeHost());
106         } catch (MalformedURLException me) {
107             throw new ServletException("Proxy URL is invalid", me);
108         }
109
110         try {
111             httpClient = buildRestClient();
112         } catch (Exception e) {
113             throw new ServletException("Build rest client failed", e);
114         }
115     }
116
117     @Override
118     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws IOException {
119         proxy(request, response, MethodEnum.GET);
120     }
121
122     @Override
123     public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
124         String userId = request.getParameter("userId");
125         String password = request.getParameter("password");
126
127         // Already sign-in
128         if (userId == null) {
129             userId = request.getHeader(USER_ID);
130         }
131
132         System.out.println("SdcProxy -> doPost userId=" + userId);
133         request.setAttribute("message", "OK");
134         if (password != null && getUser(userId, password) == null) {
135             MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(request);
136             RequestDispatcher view = request.getRequestDispatcher("login");
137             request.setAttribute("message", "ERROR: userid or password incorrect");
138             view.forward(mutableRequest, response);
139         } else {
140             if (!verifyContentType(request, response)) {
141                 return;
142             }
143             request.setAttribute(HTTP_IV_USER, userId);
144             proxy(request, response, MethodEnum.POST);
145         }
146     }
147
148     @Override
149     public void doPut(HttpServletRequest request, HttpServletResponse response) throws IOException {
150         if (!verifyContentType(request, response)) {
151             return;
152         }
153         proxy(request, response, MethodEnum.PUT);
154     }
155
156     @Override
157     public void doDelete(HttpServletRequest request, HttpServletResponse response) throws IOException {
158         proxy(request, response, MethodEnum.DELETE);
159     }
160
161     private void proxy(HttpServletRequest request, HttpServletResponse response, MethodEnum methodEnum) throws IOException {
162         String userIdHeader = getUseridFromRequest(request);
163         // new request - forward to login page
164         if (userIdHeader == null) {
165             LOGGER.debug("{} not provided. Redirecting to /login", USER_ID);
166             response.sendRedirect("/login");
167             return;
168         }
169
170         final User user = getUser(userIdHeader);
171
172         Map<String, String[]> requestParameters = request.getParameterMap();
173         String uri = getUri(request, requestParameters);
174         HttpRequestBase httpMethod = createHttpMethod(request, methodEnum, uri);
175         addHeadersToMethod(httpMethod, user, request);
176
177         try (CloseableHttpResponse closeableHttpResponse = httpClient.execute(httpMethod)) {
178             response.setStatus(closeableHttpResponse.getStatusLine().getStatusCode());
179             if (request.getRequestURI().indexOf(".svg") > -1) {
180                 response.setContentType("image/svg+xml");
181             }
182
183             if (closeableHttpResponse.getEntity() != null) {
184                 InputStream responseBodyStream = closeableHttpResponse.getEntity().getContent();
185                 Header contentEncodingHeader = closeableHttpResponse.getLastHeader("Content-Encoding");
186                 if (contentEncodingHeader != null && contentEncodingHeader.getValue().equalsIgnoreCase("gzip")) {
187                     responseBodyStream = new GZIPInputStream(responseBodyStream);
188                 }
189                 write(responseBodyStream, response.getOutputStream());
190             }
191         }
192     }
193
194     private boolean verifyContentType(HttpServletRequest request, HttpServletResponse response) throws IOException {
195         final String contentTypeHeader = request.getHeader(HttpHeaders.CONTENT_TYPE);
196         if (StringUtils.isBlank(contentTypeHeader)) {
197             response.setStatus(HttpStatus.SC_BAD_REQUEST);
198             response.getWriter().write("Missing header " + HttpHeaders.CONTENT_TYPE);
199             response.getWriter().flush();
200             return false;
201         }
202         try {
203             getContentType(request);
204         } catch (final Exception e) {
205             final String errorMsg = "Invalid content type";
206             LOGGER.debug(errorMsg, e);
207             response.setStatus(HttpStatus.SC_BAD_REQUEST);
208             response.getWriter().write(errorMsg);
209             response.getWriter().flush();
210             return false;
211         }
212         return true;
213     }
214
215     private User getUser(String userId, String password) {
216         User user = getUser(userId);
217         if (user.getPassword().equals(password)) {
218             return user;
219         }
220         return null;
221     }
222
223     private User getUser(String userId) {
224         return conf.getUsers().get(userId);
225
226     }
227
228     private List<String> getContextPaths() {
229         List<String> contextPaths = new ArrayList<>();
230         contextPaths.add(SDC1);
231         contextPaths.add(ONBOARDING);
232         contextPaths.add(STYLES);
233         contextPaths.add(SCRIPTS);
234         contextPaths.add(LANGUAGES);
235         contextPaths.add(CONFIGURATIONS);
236         return contextPaths;
237     }
238
239     private String getUri(HttpServletRequest request, Map<String, String[]> requestParameters) {
240         String suffix = request.getRequestURI();
241         if (getContextPaths().stream().anyMatch(request.getRequestURI()::contains)) {
242             suffix = alignUrlProxy(suffix);
243         }
244         StringBuilder query = alignUrlParameters(requestParameters);
245         return String.format("%s%s", url.toString() + suffix, query.toString());
246     }
247
248     private HttpRequestBase createHttpMethod(HttpServletRequest request, MethodEnum methodEnum, String uri) throws IOException {
249         HttpRequestBase proxyMethod = null;
250         ServletInputStream inputStream = null;
251         InputStreamEntity entity = null;
252
253         switch (methodEnum) {
254             case GET:
255                 proxyMethod = new HttpGet(uri);
256                 break;
257             case POST:
258                 proxyMethod = new HttpPost(uri);
259                 inputStream = request.getInputStream();
260                 entity = new InputStreamEntity(inputStream, getContentType(request));
261                 ((HttpPost) proxyMethod).setEntity(entity);
262                 break;
263             case PUT:
264                 proxyMethod = new HttpPut(uri);
265                 inputStream = request.getInputStream();
266                 entity = new InputStreamEntity(inputStream, getContentType(request));
267                 ((HttpPut) proxyMethod).setEntity(entity);
268                 break;
269             case DELETE:
270                 proxyMethod = new HttpDelete(uri);
271                 break;
272         }
273         return proxyMethod;
274     }
275
276     private ContentType getContentType(HttpServletRequest request) {
277         String contentTypeStr = request.getContentType();
278         if (contentTypeStr == null) {
279             contentTypeStr = request.getHeader("contentType");
280         }
281         ContentType contentType = ContentType.parse(contentTypeStr);
282         return ContentType.create(contentType.getMimeType());
283     }
284
285     private String getUseridFromRequest(HttpServletRequest request) {
286
287         String userIdHeader = request.getHeader(USER_ID);
288         if (userIdHeader != null) {
289             return userIdHeader;
290         }
291         Object o = request.getAttribute(HTTP_IV_USER);
292         if (o != null) {
293             return o.toString();
294         }
295         Cookie[] cookies = request.getCookies();
296
297         if (cookies != null) {
298             for (int i = 0; i < cookies.length; ++i) {
299                 if (cookies[i].getName().equals(USER_ID)) {
300                     userIdHeader = cookies[i].getValue();
301                 }
302             }
303         }
304         return userIdHeader;
305     }
306
307     private void addHeadersToMethod(HttpUriRequest proxyMethod, User user, HttpServletRequest request) {
308
309         proxyMethod.setHeader(ReservedHeaders.HTTP_IV_USER.name(), user.getUserId());
310         proxyMethod.setHeader(ReservedHeaders.USER_ID.name(), user.getUserId());
311         proxyMethod.setHeader(ReservedHeaders.HTTP_CSP_FIRSTNAME.name(), user.getFirstName());
312         proxyMethod.setHeader(ReservedHeaders.HTTP_CSP_EMAIL.name(), user.getEmail());
313         proxyMethod.setHeader(ReservedHeaders.HTTP_CSP_LASTNAME.name(), user.getLastName());
314         proxyMethod.setHeader(ReservedHeaders.HTTP_IV_REMOTE_ADDRESS.name(), "0.0.0.0");
315         proxyMethod.setHeader(ReservedHeaders.HTTP_CSP_WSTYPE.name(), "Intranet");
316         proxyMethod.setHeader(ReservedHeaders.HTTP_CSP_EMAIL.name(), "me@mail.com");
317
318         Enumeration<String> headerNames = request.getHeaderNames();
319         while (headerNames.hasMoreElements()) {
320             String headerName = headerNames.nextElement();
321             if (!RESERVED_HEADERS.contains(headerName)) {
322                 Enumeration<String> headers = request.getHeaders(headerName);
323                 while (headers.hasMoreElements()) {
324                     String headerValue = headers.nextElement();
325                     proxyMethod.setHeader(headerName, headerValue);
326                 }
327             }
328         }
329     }
330
331     private String alignUrlProxy(String requestURI) {
332
333         int i = requestURI.indexOf(ONBOARDING);
334         if (-1 != i) {
335             return requestURI.substring(i);
336         }
337
338         i = requestURI.indexOf(SDC1 + SDC1);
339         if (-1 != i) {
340             return requestURI.substring(SDC1.length());
341         }
342
343         i = requestURI.indexOf(SDC1);
344         if (-1 != i) {
345             return requestURI;
346         }
347
348         return SDC1 + requestURI;
349     }
350
351     private StringBuilder alignUrlParameters(Map<String, String[]> requestParameters) {
352         final var query = new StringBuilder();
353         for (final Entry<String, String[]> entry : requestParameters.entrySet()) {
354             for (final String value : entry.getValue()) {
355                 if (query.length() == 0) {
356                     query.append("?");
357                 } else {
358                     query.append("&");
359                 }
360                 query.append(String.format("&%s=%s", URLEncoder.encode(entry.getKey(), UTF_8), URLEncoder.encode(value, UTF_8)));
361             }
362         }
363         return query;
364     }
365
366     private void write(InputStream inputStream, OutputStream outputStream) throws IOException {
367         int b;
368         while (inputStream != null && (b = inputStream.read()) != -1) {
369             outputStream.write(b);
370         }
371         outputStream.flush();
372     }
373
374     @Override
375     public String getServletInfo() {
376         return "Http Proxy Servlet";
377     }
378
379     private CloseableHttpClient buildRestClient() throws NoSuchAlgorithmException, KeyStoreException {
380         final var builder = new SSLContextBuilder();
381         builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
382         SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(SSLContext.getDefault(),
383             NoopHostnameVerifier.INSTANCE);
384         Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
385             .register("http", new PlainConnectionSocketFactory())
386             .register("https", sslsf)
387             .build();
388         PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
389         return HttpClients.custom()
390             .setSSLSocketFactory(sslsf)
391             .setConnectionManager(cm)
392             .build();
393     }
394
395     @AllArgsConstructor
396     @Getter
397     enum ReservedHeaders {
398         HTTP_IV_USER(SdcProxy.HTTP_IV_USER), USER_ID(SdcProxy.USER_ID), HTTP_CSP_FIRSTNAME("HTTP_CSP_FIRSTNAME"), HTTP_CSP_EMAIL(
399             "HTTP_CSP_EMAIL"), HTTP_CSP_LASTNAME("HTTP_CSP_LASTNAME"), HTTP_IV_REMOTE_ADDRESS("HTTP_IV_REMOTE_ADDRESS"), HTTP_CSP_WSTYPE(
400             "HTTP_CSP_WSTYPE"), HOST("Host"), CONTENTLENGTH("Content-Length");
401
402         private final String value;
403
404     }
405
406 }