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