de235bff893affc346a919109ddeb9d9b52c1765
[sdc.git] /
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.securityutil.filters;
22
23 import org.onap.logging.ref.slf4j.ONAPLogConstants;
24 import org.openecomp.sdc.securityutil.AuthenticationCookieUtils;
25 import org.openecomp.sdc.securityutil.CipherUtilException;
26 import org.openecomp.sdc.securityutil.ISessionValidationFilterConfiguration;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29 import org.slf4j.MDC;
30 import org.apache.commons.lang.StringUtils;
31
32 import javax.servlet.Filter;
33 import javax.servlet.FilterChain;
34 import javax.servlet.FilterConfig;
35 import javax.servlet.ServletException;
36 import javax.servlet.ServletRequest;
37 import javax.servlet.ServletResponse;
38 import javax.servlet.http.Cookie;
39 import javax.servlet.http.HttpServletRequest;
40 import javax.servlet.http.HttpServletResponse;
41 import java.io.IOException;
42 import java.util.Arrays;
43 import java.util.List;
44 import java.util.UUID;
45 import java.util.concurrent.TimeUnit;
46 import java.util.stream.Collectors;
47
48 public abstract class SessionValidationFilter implements Filter {
49     private static final Logger log = LoggerFactory.getLogger(SessionValidationFilter.class.getName());
50     private ISessionValidationFilterConfiguration filterConfiguration;
51     private List<String> excludedUrls;
52
53     private static final String REQUEST_ID = ONAPLogConstants.MDCs.REQUEST_ID;
54     private static final String ONAP_REQUEST_ID_HEADER = ONAPLogConstants.Headers.REQUEST_ID;
55     private static final String REQUEST_ID_HEADER = "X-RequestID";
56     private static final String TRANSACTION_ID_HEADER = "X-TransactionId";
57     private static final String ECOMP_REQUEST_ID_HEADER = "X-ECOMP-RequestID";
58
59     private static final String PARTNER_NAME = ONAPLogConstants.MDCs.PARTNER_NAME;
60     private static final String USER_ID_HEADER = "USER_ID";
61     private static final String ONAP_PARTNER_NAME_HEADER = ONAPLogConstants.Headers.PARTNER_NAME;
62     private static final String USER_AGENT_HEADER = "User-Agent";
63     private static final String UNKNOWN = "UNKNOWN";
64
65
66     public abstract ISessionValidationFilterConfiguration getFilterConfiguration();
67     protected abstract Cookie addRoleToCookie(Cookie updatedCookie);
68     protected abstract boolean isRoleValid(Cookie cookie);
69
70     @Override
71     public final void init(FilterConfig filterConfig) throws ServletException {
72         filterConfiguration = getFilterConfiguration();
73         excludedUrls = filterConfiguration.getExcludedUrls();
74     }
75
76     @Override
77     public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
78         final HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
79         final HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
80
81         long startTime = System.nanoTime();
82         fillMDCFromHeaders(httpRequest);
83         log.debug("SessionValidationFilter: Validation started, received request with URL {}", httpRequest.getRequestURL());
84
85         // request preprocessing
86         boolean isContinueProcessing = preProcessingRequest(servletRequest, servletResponse, filterChain, httpRequest, httpResponse, startTime);
87         List<Cookie> cookies = null;
88         Cookie extractedCookie = null;
89
90         // request processing
91         if (isContinueProcessing) {
92             cookies = extractAuthenticationCookies(httpRequest.getCookies());
93             extractedCookie = cookies.get(0);
94             isContinueProcessing = processRequest(httpRequest, httpResponse, extractedCookie);
95         }
96
97         // response processing
98         if(isContinueProcessing){
99             log.debug("SessionValidationFilter: Cookie from request {} is valid, passing request to session extension ...", httpRequest.getRequestURL());
100             Cookie updatedCookie = processResponse(extractedCookie);
101             cleanResponceFromLeftoverCookies(httpResponse, cookies);
102             log.debug("SessionValidationFilter: request {} passed all validations, passing request to endpoint ...", httpRequest.getRequestURL());
103             httpResponse.addCookie(updatedCookie);
104             long durationSec = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime);
105             long durationMil = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime);
106             log.debug("SessionValidationFilter: Validation ended, running time for URL {} is: {} seconds {} miliseconds", httpRequest.getPathInfo(), durationSec, durationMil);
107             filterChain.doFilter(servletRequest, httpResponse);
108         }
109     }
110
111
112     private boolean preProcessingRequest(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain, HttpServletRequest httpRequest, HttpServletResponse httpResponse, long startTime) throws IOException, ServletException {
113
114         boolean isPreProcessingSucceeded = true;
115         if (isUrlFromWhiteList(httpRequest)) {
116             log.debug("SessionValidationFilter: URL {} excluded from access validation , passing request to endpoint ... ", httpRequest.getRequestURL());
117             long durationSec = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - startTime);
118             long durationMil = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - startTime);
119             log.debug("SessionValidationFilter: Validation ended, running time for URL {} is: {} seconds {} miliseconds", httpRequest.getPathInfo(), durationSec, durationMil);
120             filterChain.doFilter(servletRequest, servletResponse);
121             isPreProcessingSucceeded = false;
122
123         } else if (!isCookiePresent(httpRequest.getCookies())) {
124             //redirect to portal app
125             log.debug("SessionValidationFilter: Cookie from request {} is not valid, redirecting request to portal", httpRequest.getRequestURL());
126             httpResponse.sendRedirect(filterConfiguration.getRedirectURL());
127             isPreProcessingSucceeded = false;
128         }
129         return isPreProcessingSucceeded;
130     }
131
132     private boolean processRequest(HttpServletRequest httpRequest, HttpServletResponse httpResponse, Cookie cookie) throws IOException {
133         boolean isProcessSuccessful= true;
134         try {
135             if (AuthenticationCookieUtils.isSessionExpired(cookie, filterConfiguration)) {
136                 //redirect to portal app
137                 log.debug("SessionValidationFilter: Session is expired, redirecting request {} to portal", httpRequest.getRequestURL());
138                 httpResponse.sendRedirect(filterConfiguration.getRedirectURL());
139                 isProcessSuccessful = false;
140             }
141         } catch (CipherUtilException e) {
142             log.error("SessionValidationFilter: Cookie decryption error : {}", e.getMessage());
143             log.debug("SessionValidationFilter: Cookie decryption error : {}", e.getMessage(), e);
144             isProcessSuccessful = false;
145         }
146
147         if (!isRoleValid(cookie)) {
148             //redirect to portal app
149             log.debug("SessionValidationFilter: Role is not valid, redirecting request {} to portal", httpRequest.getRequestURL());
150             httpResponse.sendRedirect(filterConfiguration.getRedirectURL());
151             isProcessSuccessful = false;
152         }
153         return isProcessSuccessful;
154     }
155
156     private Cookie processResponse(Cookie cookie) throws IOException, ServletException {
157         Cookie updatedCookie;
158         try {
159             updatedCookie = AuthenticationCookieUtils.updateSessionTime(cookie, filterConfiguration);
160         } catch (CipherUtilException e) {
161             log.error("SessionValidationFilter: Cookie cipher error ...");
162             log.debug("SessionValidationFilter: Cookie cipher error : {}", e.getMessage(), e);
163             throw new ServletException(e.getMessage());
164         }
165         updatedCookie = addRoleToCookie(updatedCookie);
166         return updatedCookie;
167     }
168
169     private boolean isCookiePresent(Cookie[] cookies) {
170         if (cookies == null) {
171             return false;
172         }
173         String actualCookieName = filterConfiguration.getCookieName();
174         boolean isPresent = Arrays.stream(cookies).anyMatch(c -> isCookieNameMatch(actualCookieName, c));
175         if (!isPresent) {
176             log.error("SessionValidationFilter: Session Validation Cookie missing ...");
177             return false;
178         }
179         return true;
180     }
181
182     private List<Cookie> extractAuthenticationCookies(Cookie[] cookies) {
183         String actualCookieName = filterConfiguration.getCookieName();
184         log.debug("SessionValidationFilter: Extracting authentication cookies, {} cookies in request", cookies.length);
185         List<Cookie> authenticationCookies = Arrays.stream(cookies).filter(c -> isCookieNameMatch(actualCookieName, c)).collect(Collectors.toList());
186         log.debug("SessionValidationFilter: Extracted {} authentication cookies from request", authenticationCookies.size());
187         if( authenticationCookies.size() > 1 ){
188             authenticationCookies.forEach( cookie -> log.debug("SessionValidationFilter: Multiple cookies found cookie name, {} cookie value {}", cookie.getName(), cookie.getValue()));
189         }
190         return authenticationCookies;
191     }
192
193
194     // use contains for matching due issue with ecomp portal ( change cookie name, add prefix ), temp solution
195     private boolean isCookieNameMatch(String actualCookieName, Cookie c) {
196         return c.getName().contains(actualCookieName);
197     }
198
199     private boolean isUrlFromWhiteList(HttpServletRequest httpRequest) {
200         if (httpRequest.getPathInfo() == null){
201             final String servletPath = httpRequest.getServletPath().toLowerCase();
202             log.debug("SessionValidationFilter: pathInfo is null, trying to check by servlet path white list validation -> ServletPath: {} ", servletPath);
203             return excludedUrls.stream().
204                     anyMatch( e -> servletPath.matches(e));
205         }
206         String pathInfo = httpRequest.getPathInfo().toLowerCase();
207         log.debug("SessionValidationFilter: white list validation ->  PathInfo: {} ", pathInfo);
208         return excludedUrls.stream().
209                 anyMatch( e -> pathInfo.matches(e));
210     }
211
212     private void cleanResponceFromLeftoverCookies(HttpServletResponse httpResponse, List<Cookie> cookiesList) {
213         for (Cookie cookie:cookiesList){
214             Cookie cleanCookie = AuthenticationCookieUtils.createUpdatedCookie(cookie, null, filterConfiguration);
215             cleanCookie.setMaxAge(0);
216             log.debug("SessionValidationFilter Cleaning Cookie cookie name: {} added to responce", cleanCookie.getName());
217             httpResponse.addCookie(cleanCookie);
218         }
219     }
220
221     public static void fillMDCFromHeaders(HttpServletRequest httpServletRequest) {
222         fillRequestIdFromHeader(httpServletRequest);
223         fillPartnerNameFromHeader(httpServletRequest);
224
225     }
226
227     private static void fillRequestIdFromHeader(HttpServletRequest httpServletRequest){
228         if (MDC.get(REQUEST_ID) == null) {
229             if (StringUtils.isNotEmpty(httpServletRequest.getHeader(ONAP_REQUEST_ID_HEADER))) {
230                 MDC.put(REQUEST_ID, httpServletRequest.getHeader(ONAP_REQUEST_ID_HEADER));
231             } else if (StringUtils.isNotEmpty(httpServletRequest.getHeader(REQUEST_ID_HEADER))) {
232                 MDC.put(REQUEST_ID, httpServletRequest.getHeader(REQUEST_ID_HEADER));
233             } else if (StringUtils.isNotEmpty(httpServletRequest.getHeader(TRANSACTION_ID_HEADER))) {
234                 MDC.put(REQUEST_ID, httpServletRequest.getHeader(TRANSACTION_ID_HEADER));
235             } else if (StringUtils.isNotEmpty(httpServletRequest.getHeader(ECOMP_REQUEST_ID_HEADER))) {
236                 MDC.put(REQUEST_ID, httpServletRequest.getHeader(ECOMP_REQUEST_ID_HEADER));
237             } else {
238                 MDC.put(REQUEST_ID, UUID.randomUUID().toString());
239             }
240         }
241     }
242
243     private static void fillPartnerNameFromHeader(HttpServletRequest httpServletRequest){
244         if (MDC.get(PARTNER_NAME) == null) {
245             if (StringUtils.isNotEmpty(httpServletRequest.getHeader(USER_ID_HEADER))) {
246                 MDC.put(PARTNER_NAME, httpServletRequest.getHeader(USER_ID_HEADER));
247             } else if (StringUtils.isNotEmpty(httpServletRequest.getHeader(ONAP_PARTNER_NAME_HEADER))) {
248                 MDC.put(PARTNER_NAME, httpServletRequest.getHeader(ONAP_PARTNER_NAME_HEADER));
249             } else if (StringUtils.isNotEmpty(httpServletRequest.getHeader(USER_AGENT_HEADER))) {
250                 MDC.put(PARTNER_NAME, httpServletRequest.getHeader(USER_AGENT_HEADER));
251             }  else {
252                 MDC.put(PARTNER_NAME, UNKNOWN);
253             }
254         }
255     }
256
257
258     @Override
259     public void destroy() {
260
261     }
262 }