fix security vulnerability
[sdc.git] / catalog-fe / src / main / java / org / openecomp / sdc / fe / servlets / PortalServlet.java
1 /*-
2  * ============LICENSE_START=======================================================
3  * SDC
4  * ================================================================================
5  * Copyright (C) 2017 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 package org.openecomp.sdc.fe.servlets;
21
22 import java.io.IOException;
23 import java.util.Enumeration;
24 import java.util.List;
25 import javax.servlet.RequestDispatcher;
26 import javax.servlet.ServletException;
27 import javax.servlet.http.Cookie;
28 import javax.servlet.http.HttpServlet;
29 import javax.servlet.http.HttpServletRequest;
30 import javax.servlet.http.HttpServletResponse;
31 import javax.ws.rs.GET;
32 import javax.ws.rs.Path;
33 import javax.ws.rs.core.Context;
34 import org.onap.portalsdk.core.onboarding.exception.CipherUtilException;
35 import org.onap.portalsdk.core.onboarding.util.CipherUtil;
36 import org.onap.sdc.security.AuthenticationCookie;
37 import org.onap.sdc.security.RepresentationUtils;
38 import org.openecomp.sdc.common.impl.MutableHttpServletRequest;
39 import org.openecomp.sdc.common.log.wrappers.Logger;
40 import org.openecomp.sdc.common.util.ValidationUtils;
41 import org.openecomp.sdc.fe.Constants;
42 import org.openecomp.sdc.fe.config.Configuration;
43 import org.openecomp.sdc.fe.config.ConfigurationManager;
44 import org.openecomp.sdc.fe.config.FeEcompErrorManager;
45
46 /**
47  * Root resource (exposed at "/" path)
48  */
49 @Path("/")
50 public class PortalServlet extends HttpServlet {
51
52     public static final String MISSING_HEADERS_MSG = "Missing Headers In Request";
53     private static final long serialVersionUID = 1L;
54     private static final String AUTHORIZATION_ERROR_MSG = "Autherization error";
55     private static final String NEW_LINE = System.getProperty("line.separator");
56     private static Logger log = Logger.getLogger(PortalServlet.class.getName());
57
58     private static String getUserIdFromCookie(HttpServletRequest request) throws CipherUtilException {
59         String userId = "";
60         Cookie[] cookies = request.getCookies();
61         Cookie userIdcookie = null;
62         if (cookies != null) {
63             for (Cookie cookie : cookies) {
64                 if (cookie.getName().equals(Constants.ECOMP_PORTAL_COOKIE)) {
65                     userIdcookie = cookie;
66                 }
67             }
68         }
69         if (userIdcookie != null) {
70             userId = CipherUtil.decrypt(userIdcookie.getValue());
71         }
72         return userId;
73     }
74
75     private static String getValueFromCookie(HttpServletRequest request, String cookieName) {
76         String value = "";
77         Cookie[] cookies = request.getCookies();
78         Cookie valueFromCookie = null;
79         if (cookies != null) {
80             for (Cookie cookie : cookies) {
81                 if (cookie.getName().endsWith(cookieName)) {
82                     valueFromCookie = cookie;
83                 }
84             }
85         }
86         if (valueFromCookie != null) {
87             value = valueFromCookie.getValue();
88         }
89         return value;
90     }
91
92     /**
93      * Entry point from ECOMP portal
94      */
95     @GET
96     @Path("/portal")
97     @Override
98     public void doGet(@Context final HttpServletRequest request, @Context final HttpServletResponse response) {
99         try {
100             addRequestHeadersUsingWebseal(request, response);
101         } catch (Exception e) {
102             FeEcompErrorManager.getInstance().logFePortalServletError("Portal Servlet");
103             log.error("Error during getting portal page", e);
104         }
105     }
106
107     /**
108      * Building new HTTP request and setting headers for the request The request will dispatch to index.html
109      *
110      * @param request
111      * @param response
112      * @throws ServletException
113      * @throws IOException
114      */
115     private void addRequestHeadersUsingWebseal(final HttpServletRequest request, final HttpServletResponse response)
116         throws ServletException, IOException {
117         response.setContentType("text/html");
118         // Create new request object to dispatch
119         MutableHttpServletRequest mutableRequest = new MutableHttpServletRequest(request);
120         // Get configuration object (reads data from configuration.yaml)
121         Configuration configuration = getConfiguration(request);
122         // Check if we got header from webseal
123         String userId = request.getHeader(Constants.WEBSEAL_USER_ID_HEADER);
124         if (null == userId) {
125             // Authentication via ecomp portal
126             try {
127                 String userIdFromCookie = getUserIdFromCookie(request);
128                 if (("").equals(userIdFromCookie)) {
129                     // This is probably a webseal request, so missing header in request should be printed.
130                     response.sendError(HttpServletResponse.SC_USE_PROXY, MISSING_HEADERS_MSG);
131                 }
132                 userId = userIdFromCookie;
133             } catch (Exception e) {
134                 response.sendError(HttpServletResponse.SC_USE_PROXY, AUTHORIZATION_ERROR_MSG);
135                 log.error("Error during adding request header", e);
136             }
137         }
138         // Replace webseal header with open source header
139         mutableRequest.putHeader(Constants.USER_ID, userId);
140         // Getting identification headers from configuration.yaml
141
142         // (identificationHeaderFields) and setting them to new request
143
144         // mutableRequest
145         List<List<String>> identificationHeaderFields = configuration.getIdentificationHeaderFields();
146         for (List<String> possibleHeadersToRecieve : identificationHeaderFields) {
147             String allowedHeaderToPass = possibleHeadersToRecieve.get(0);
148             setNewHeader(possibleHeadersToRecieve, allowedHeaderToPass, request, mutableRequest);
149         }
150         // Getting optional headers from configuration.yaml
151
152         // (optionalHeaderFields) and setting them to new request mutableRequest
153         List<List<String>> optionalHeaderFields = configuration.getOptionalHeaderFields();
154         for (List<String> possibleHeadersToRecieve : optionalHeaderFields) {
155             String allowedHeaderToPass = possibleHeadersToRecieve.get(0);
156             setNewHeader(possibleHeadersToRecieve, allowedHeaderToPass, request, mutableRequest);
157         }
158         // Print headers from original request for debug purposes
159         printHeaders(request);
160         // In case using webseal, validate all mandatory headers (identificationHeaderFields) are included in the new request (mutableRequest).
161
162         // Via ecomp portal do not need to check the headers.
163         boolean allHeadersExist = true;
164         if (null != request.getHeader(Constants.WEBSEAL_USER_ID_HEADER)) {
165             allHeadersExist = checkHeaders(mutableRequest);
166         }
167         if (allHeadersExist) {
168             addCookies(response, mutableRequest, getMandatoryHeaders(request));
169             addCookies(response, mutableRequest, getOptionalHeaders(request));
170             getValueFromCookie(request, Constants.HTTP_CSP_FIRSTNAME);
171             getValueFromCookie(request, Constants.HTTP_CSP_LASTNAME);
172             //To be fixed
173
174             //addAuthCookie(response, userId, firstNameFromCookie, lastNameFromCookie);
175             RequestDispatcher rd = request.getRequestDispatcher("index.html");
176             rd.forward(mutableRequest, response);
177         } else {
178             response.sendError(HttpServletResponse.SC_USE_PROXY, MISSING_HEADERS_MSG);
179         }
180     }
181
182     boolean addAuthCookie(HttpServletResponse response, String userId, String firstName, String lastName) throws IOException {
183         boolean isBuildCookieCompleted = true;
184         Cookie authCookie = null;
185         Configuration.CookieConfig confCookie = ConfigurationManager.getConfigurationManager().getConfiguration().getAuthCookie();
186         //create authentication and send it to encryption
187         String encryptedCookie = "";
188         try {
189             AuthenticationCookie authenticationCookie = new AuthenticationCookie(userId, firstName, lastName);
190             String cookieAsJson = RepresentationUtils.toRepresentation(authenticationCookie);
191             encryptedCookie = org.onap.sdc.security.CipherUtil.encryptPKC(cookieAsJson, confCookie.getSecurityKey());
192         } catch (Exception e) {
193             isBuildCookieCompleted = false;
194             log.error(" Cookie Encryption failed ", e);
195         }
196         authCookie = new Cookie(confCookie.getCookieName(), encryptedCookie);
197         authCookie.setPath(confCookie.getPath());
198         authCookie.setDomain(confCookie.getDomain());
199         authCookie.setHttpOnly(true);
200         // add generated cookie to response
201         if (isBuildCookieCompleted) {
202             response.addCookie(authCookie);
203             return true;
204         }
205         response.sendError(HttpServletResponse.SC_UNAUTHORIZED, AUTHORIZATION_ERROR_MSG);
206         return false;
207     }
208
209     /**
210      * Print all request headers to the log
211      *
212      * @param request
213      */
214     private void printHeaders(HttpServletRequest request) {
215         if (log.isDebugEnabled()) {
216             StringBuilder builder = new StringBuilder();
217             String sessionId = "";
218             if (request.getSession() != null) {
219                 String id = request.getSession().getId();
220                 if (id != null) {
221                     sessionId = id;
222                 }
223             }
224             builder.append("Receiving request with headers:" + NEW_LINE);
225             log.debug("{}", request.getHeaderNames());
226             @SuppressWarnings("unchecked") Enumeration<String> headerNames = request.getHeaderNames();
227             if (headerNames != null) {
228                 while (headerNames.hasMoreElements()) {
229                     String headerName = headerNames.nextElement();
230                     String headerValue = request.getHeader(headerName);
231                     builder.append("session " + sessionId + " header: name = " + headerName + ", value = " + headerValue + NEW_LINE);
232                 }
233             }
234             log.debug(builder.toString());
235         }
236     }
237
238     /**
239      * Add cookies (that where set in the new request headers) in the response Using DefaultHTTPUtilities Object to prevent CRLF injection in HTTP
240      * headers.
241      *
242      * @param response
243      * @param request
244      * @param headers
245      */
246     private void addCookies(final HttpServletResponse response, final HttpServletRequest request, final String[] headers) {
247         for (var i = 0; i < headers.length; i++) {
248             final var currHeader = ValidationUtils.sanitizeInputString(headers[i]);
249             final var headerValue = ValidationUtils.sanitizeInputString(request.getHeader(currHeader));
250             if (headerValue != null) {
251                 final var cookie = new Cookie(currHeader, headerValue);
252                 cookie.setSecure(true);
253                 response.addCookie(cookie);
254             }
255         }
256     }
257
258     /**
259      * Get mandatory headers (identificationHeaderFields) String array, and checks that each header exists in the new request
260      *
261      * @param request
262      * @return boolean
263      */
264     private boolean checkHeaders(HttpServletRequest request) {
265         String[] mandatoryHeaders = getMandatoryHeaders(request);
266         boolean allHeadersExist = true;
267         for (int i = 0; i < mandatoryHeaders.length; i++) {
268             String headerValue = request.getHeader(mandatoryHeaders[i]);
269             if (headerValue == null) {
270                 allHeadersExist = false;
271                 break;
272             }
273         }
274         return allHeadersExist;
275     }
276
277     /**
278      * Get mandatory headers (identificationHeaderFields) from configuration.yaml file and return String[]
279      *
280      * @param request
281      * @return String[]
282      */
283     private String[] getMandatoryHeaders(HttpServletRequest request) {
284         Configuration configuration = getConfiguration(request);
285         List<List<String>> identificationHeaderFields = configuration.getIdentificationHeaderFields();
286         String[] mandatoryHeaders = new String[identificationHeaderFields.size()];
287         for (int i = 0; i < identificationHeaderFields.size(); i++) {
288             mandatoryHeaders[i] = identificationHeaderFields.get(i).get(0);
289         }
290         return mandatoryHeaders;
291     }
292
293     /**
294      * Get optional headers (optionalHeaderFields) from configuration.yaml file and return String[]
295      *
296      * @param request
297      * @return String[]
298      */
299     private String[] getOptionalHeaders(HttpServletRequest request) {
300         Configuration configuration = getConfiguration(request);
301         List<List<String>> optionalHeaderFields = configuration.getOptionalHeaderFields();
302         String[] optionalHeaders = new String[optionalHeaderFields.size()];
303         for (int i = 0; i < optionalHeaderFields.size(); i++) {
304             optionalHeaders[i] = optionalHeaderFields.get(i).get(0);
305         }
306         return optionalHeaders;
307     }
308
309     /**
310      * Return Configuration object to read from configuration.yaml
311      *
312      * @param request
313      * @return Configuration
314      */
315     private Configuration getConfiguration(HttpServletRequest request) {
316         ConfigurationManager configManager = (ConfigurationManager) request.getSession().getServletContext()
317             .getAttribute(org.openecomp.sdc.common.api.Constants.CONFIGURATION_MANAGER_ATTR);
318         return configManager.getConfiguration();
319     }
320
321     private boolean setNewHeader(List<String> possibleOldHeaders, String newHeaderToSet, HttpServletRequest oldRequest,
322                                  MutableHttpServletRequest newRequest) {
323         boolean newHeaderIsSet = false;
324         for (int i = 0; i < possibleOldHeaders.size() && !newHeaderIsSet; i++) {
325             String headerValue = oldRequest.getHeader(possibleOldHeaders.get(i));
326             if (headerValue != null) {
327                 newRequest.putHeader(newHeaderToSet, headerValue);
328                 newHeaderIsSet = true;
329             }
330         }
331         return newHeaderIsSet;
332     }
333 }