Fix encoding/decoding issue
[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.http.Header;
54 import org.apache.http.client.methods.CloseableHttpResponse;
55 import org.apache.http.client.methods.HttpDelete;
56 import org.apache.http.client.methods.HttpGet;
57 import org.apache.http.client.methods.HttpPost;
58 import org.apache.http.client.methods.HttpPut;
59 import org.apache.http.client.methods.HttpRequestBase;
60 import org.apache.http.client.methods.HttpUriRequest;
61 import org.apache.http.config.Registry;
62 import org.apache.http.config.RegistryBuilder;
63 import org.apache.http.conn.socket.ConnectionSocketFactory;
64 import org.apache.http.conn.socket.PlainConnectionSocketFactory;
65 import org.apache.http.conn.ssl.NoopHostnameVerifier;
66 import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
67 import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
68 import org.apache.http.entity.ContentType;
69 import org.apache.http.entity.InputStreamEntity;
70 import org.apache.http.impl.client.CloseableHttpClient;
71 import org.apache.http.impl.client.HttpClients;
72 import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
73 import org.apache.http.ssl.SSLContextBuilder;
74 import org.openecomp.sdc.webseal.simulator.conf.Conf;
75
76 public class SdcProxy extends HttpServlet {
77
78     private static final long serialVersionUID = 1L;
79     private static final Set<String> RESERVED_HEADERS =
80         Arrays.stream(ReservedHeaders.values()).map(ReservedHeaders::getValue).collect(Collectors.toSet());
81     private static final String USER_ID = "USER_ID";
82     private static final String HTTP_IV_USER = "HTTP_IV_USER";
83     private static final String SDC1 = "/sdc1";
84     private static final String ONBOARDING = "/onboarding/";
85     private static final String SCRIPTS = "/scripts";
86     private static final String STYLES = "/styles";
87     private static final String LANGUAGES = "/languages";
88     private static final String CONFIGURATIONS = "/configurations";
89     private URL url;
90     private CloseableHttpClient httpClient;
91     private Conf conf;
92
93     @Override
94     public void init(ServletConfig config) throws ServletException {
95         super.init(config);
96         conf = Conf.getInstance();
97         try {
98             url = new URL(conf.getFeHost());
99         } catch (MalformedURLException me) {
100             throw new ServletException("Proxy URL is invalid", me);
101         }
102
103         try {
104             httpClient = buildRestClient();
105         } catch (Exception e) {
106             throw new ServletException("Build rest client failed", e);
107         }
108     }
109
110     @Override
111     protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
112         proxy(request, response, MethodEnum.GET);
113     }
114
115     @Override
116     public void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
117
118         String userId = request.getParameter("userId");
119         String password = request.getParameter("password");
120
121         // Already sign-in
122         if (userId == null) {
123             userId = request.getHeader(USER_ID);
124         }
125
126         System.out.println("SdcProxy -> doPost userId=" + userId);
127         request.setAttribute("message", "OK");
128         if (password != null && getUser(userId, password) == null) {
129             MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(request);
130             RequestDispatcher view = request.getRequestDispatcher("login");
131             request.setAttribute("message", "ERROR: userid or password incorect");
132             view.forward(mutableRequest, response);
133         } else {
134             System.out.println("SdcProxy -> doPost going to doGet");
135             request.setAttribute(HTTP_IV_USER, userId);
136             proxy(request, response, MethodEnum.POST);
137         }
138     }
139
140     @Override
141     public void doPut(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
142         proxy(request, response, MethodEnum.PUT);
143     }
144
145     @Override
146     public void doDelete(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
147         proxy(request, response, MethodEnum.DELETE);
148     }
149
150     private void proxy(HttpServletRequest request, HttpServletResponse response, MethodEnum methodEnum) throws IOException {
151
152         Map<String, String[]> requestParameters = request.getParameterMap();
153         String userIdHeader = getUseridFromRequest(request);
154         // new request - forward to login page
155         if (userIdHeader == null) {
156             System.out.print("Going to login");
157             response.sendRedirect("/login");
158             return;
159         }
160
161         final User user = getUser(userIdHeader);
162
163         String uri = getUri(request, requestParameters);
164         HttpRequestBase httpMethod = createHttpMethod(request, methodEnum, uri);
165         addHeadersToMethod(httpMethod, user, request);
166
167         try (CloseableHttpResponse closeableHttpResponse = httpClient.execute(httpMethod)) {
168             response.setStatus(closeableHttpResponse.getStatusLine().getStatusCode());
169             if (request.getRequestURI().indexOf(".svg") > -1) {
170                 response.setContentType("image/svg+xml");
171             }
172
173             if (closeableHttpResponse.getEntity() != null) {
174                 InputStream responseBodyStream = closeableHttpResponse.getEntity().getContent();
175                 Header contentEncodingHeader = closeableHttpResponse.getLastHeader("Content-Encoding");
176                 if (contentEncodingHeader != null && contentEncodingHeader.getValue().equalsIgnoreCase("gzip")) {
177                     responseBodyStream = new GZIPInputStream(responseBodyStream);
178                 }
179                 write(responseBodyStream, response.getOutputStream());
180             }
181         }
182     }
183
184     private User getUser(String userId, String password) {
185         User user = getUser(userId);
186         if (user.getPassword().equals(password)) {
187             return user;
188         }
189         return null;
190     }
191
192     private User getUser(String userId) {
193         return conf.getUsers().get(userId);
194
195     }
196
197     private List<String> getContextPaths() {
198         List<String> contextPaths = new ArrayList<>();
199         contextPaths.add(SDC1);
200         contextPaths.add(ONBOARDING);
201         contextPaths.add(STYLES);
202         contextPaths.add(SCRIPTS);
203         contextPaths.add(LANGUAGES);
204         contextPaths.add(CONFIGURATIONS);
205         return contextPaths;
206     }
207
208     private String getUri(HttpServletRequest request, Map<String, String[]> requestParameters) {
209         String suffix = request.getRequestURI();
210         if (getContextPaths().stream().anyMatch(request.getRequestURI()::contains)) {
211             suffix = alignUrlProxy(suffix);
212         }
213         StringBuilder query = alignUrlParameters(requestParameters);
214         return String.format("%s%s", url.toString() + suffix, query.toString());
215     }
216
217     private HttpRequestBase createHttpMethod(HttpServletRequest request, MethodEnum methodEnum, String uri) throws IOException {
218         HttpRequestBase proxyMethod = null;
219         ServletInputStream inputStream = null;
220         InputStreamEntity entity = null;
221
222         switch (methodEnum) {
223             case GET:
224                 proxyMethod = new HttpGet(uri);
225                 break;
226             case POST:
227                 proxyMethod = new HttpPost(uri);
228                 inputStream = request.getInputStream();
229                 entity = new InputStreamEntity(inputStream, getContentType(request));
230                 ((HttpPost) proxyMethod).setEntity(entity);
231                 break;
232             case PUT:
233                 proxyMethod = new HttpPut(uri);
234                 inputStream = request.getInputStream();
235                 entity = new InputStreamEntity(inputStream, getContentType(request));
236                 ((HttpPut) proxyMethod).setEntity(entity);
237                 break;
238             case DELETE:
239                 proxyMethod = new HttpDelete(uri);
240                 break;
241         }
242         return proxyMethod;
243     }
244
245     private ContentType getContentType(HttpServletRequest request) {
246         String contentTypeStr = request.getContentType();
247         if (contentTypeStr == null) {
248             contentTypeStr = request.getHeader("contentType");
249         }
250         ContentType contentType = ContentType.parse(contentTypeStr);
251         return ContentType.create(contentType.getMimeType());
252     }
253
254     private String getUseridFromRequest(HttpServletRequest request) {
255
256         String userIdHeader = request.getHeader(USER_ID);
257         if (userIdHeader != null) {
258             return userIdHeader;
259         }
260         Object o = request.getAttribute(HTTP_IV_USER);
261         if (o != null) {
262             return o.toString();
263         }
264         Cookie[] cookies = request.getCookies();
265
266         if (cookies != null) {
267             for (int i = 0; i < cookies.length; ++i) {
268                 if (cookies[i].getName().equals(USER_ID)) {
269                     userIdHeader = cookies[i].getValue();
270                 }
271             }
272         }
273         return userIdHeader;
274     }
275
276     private void addHeadersToMethod(HttpUriRequest proxyMethod, User user, HttpServletRequest request) {
277
278         proxyMethod.setHeader(ReservedHeaders.HTTP_IV_USER.name(), user.getUserId());
279         proxyMethod.setHeader(ReservedHeaders.USER_ID.name(), user.getUserId());
280         proxyMethod.setHeader(ReservedHeaders.HTTP_CSP_FIRSTNAME.name(), user.getFirstName());
281         proxyMethod.setHeader(ReservedHeaders.HTTP_CSP_EMAIL.name(), user.getEmail());
282         proxyMethod.setHeader(ReservedHeaders.HTTP_CSP_LASTNAME.name(), user.getLastName());
283         proxyMethod.setHeader(ReservedHeaders.HTTP_IV_REMOTE_ADDRESS.name(), "0.0.0.0");
284         proxyMethod.setHeader(ReservedHeaders.HTTP_CSP_WSTYPE.name(), "Intranet");
285         proxyMethod.setHeader(ReservedHeaders.HTTP_CSP_EMAIL.name(), "me@mail.com");
286
287         Enumeration<String> headerNames = request.getHeaderNames();
288         while (headerNames.hasMoreElements()) {
289             String headerName = headerNames.nextElement();
290             if (!RESERVED_HEADERS.contains(headerName)) {
291                 Enumeration<String> headers = request.getHeaders(headerName);
292                 while (headers.hasMoreElements()) {
293                     String headerValue = headers.nextElement();
294                     proxyMethod.setHeader(headerName, headerValue);
295                 }
296             }
297         }
298     }
299
300     private String alignUrlProxy(String requestURI) {
301
302         int i = requestURI.indexOf(ONBOARDING);
303         if (-1 != i) {
304             return requestURI.substring(i);
305         }
306
307         i = requestURI.indexOf(SDC1 + SDC1);
308         if (-1 != i) {
309             return requestURI.substring(SDC1.length());
310         }
311
312         i = requestURI.indexOf(SDC1);
313         if (-1 != i) {
314             return requestURI;
315         }
316
317         return SDC1 + requestURI;
318     }
319
320     private StringBuilder alignUrlParameters(Map<String, String[]> requestParameters) {
321         final var query = new StringBuilder();
322         for (final Entry<String, String[]> entry : requestParameters.entrySet()) {
323             for (final String value : entry.getValue()) {
324                 if (query.length() == 0) {
325                     query.append("?");
326                 } else {
327                     query.append("&");
328                 }
329                 query.append(String.format("&%s=%s", URLEncoder.encode(entry.getKey(), UTF_8), URLEncoder.encode(value, UTF_8)));
330             }
331         }
332         return query;
333     }
334
335     private void write(InputStream inputStream, OutputStream outputStream) throws IOException {
336         int b;
337         while (inputStream != null && (b = inputStream.read()) != -1) {
338             outputStream.write(b);
339         }
340         outputStream.flush();
341     }
342
343     @Override
344     public String getServletInfo() {
345         return "Http Proxy Servlet";
346     }
347
348     private CloseableHttpClient buildRestClient() throws NoSuchAlgorithmException, KeyStoreException {
349         final var builder = new SSLContextBuilder();
350         builder.loadTrustMaterial(null, new TrustSelfSignedStrategy());
351         SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(SSLContext.getDefault(),
352             NoopHostnameVerifier.INSTANCE);
353         Registry<ConnectionSocketFactory> registry = RegistryBuilder.<ConnectionSocketFactory>create()
354             .register("http", new PlainConnectionSocketFactory())
355             .register("https", sslsf)
356             .build();
357         PoolingHttpClientConnectionManager cm = new PoolingHttpClientConnectionManager(registry);
358         return HttpClients.custom()
359             .setSSLSocketFactory(sslsf)
360             .setConnectionManager(cm)
361             .build();
362     }
363
364     @AllArgsConstructor
365     @Getter
366     enum ReservedHeaders {
367         HTTP_IV_USER(SdcProxy.HTTP_IV_USER), USER_ID(SdcProxy.USER_ID), HTTP_CSP_FIRSTNAME("HTTP_CSP_FIRSTNAME"), HTTP_CSP_EMAIL(
368             "HTTP_CSP_EMAIL"), HTTP_CSP_LASTNAME("HTTP_CSP_LASTNAME"), HTTP_IV_REMOTE_ADDRESS("HTTP_IV_REMOTE_ADDRESS"), HTTP_CSP_WSTYPE(
369             "HTTP_CSP_WSTYPE"), HOST("Host"), CONTENTLENGTH("Content-Length");
370
371         private final String value;
372
373     }
374
375 }