Added oparent to sdc main
[sdc.git] / openecomp-be / backend / openecomp-sdc-security-util / src / main / java / org / openecomp / sdc / securityutil / filters / SessionValidationFilter.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.securityutil.filters;
22
23 import org.openecomp.sdc.securityutil.AuthenticationCookieUtils;
24 import org.openecomp.sdc.securityutil.CipherUtilException;
25 import org.openecomp.sdc.securityutil.ISessionValidationFilterConfiguration;
26 import org.slf4j.Logger;
27 import org.slf4j.LoggerFactory;
28
29 import javax.servlet.Filter;
30 import javax.servlet.FilterChain;
31 import javax.servlet.FilterConfig;
32 import javax.servlet.ServletException;
33 import javax.servlet.ServletRequest;
34 import javax.servlet.ServletResponse;
35 import javax.servlet.http.Cookie;
36 import javax.servlet.http.HttpServletRequest;
37 import javax.servlet.http.HttpServletResponse;
38 import java.io.IOException;
39 import java.util.Arrays;
40 import java.util.List;
41 import java.util.concurrent.TimeUnit;
42 import java.util.stream.Collectors;
43
44 public abstract class SessionValidationFilter implements Filter {
45     private static final Logger log = LoggerFactory.getLogger(SessionValidationFilter.class.getName());
46     private ISessionValidationFilterConfiguration filterConfiguration;
47     private List<String> excludedUrls;
48
49     public abstract ISessionValidationFilterConfiguration getFilterConfiguration();
50     protected abstract Cookie addRoleToCookie(Cookie updatedCookie);
51     protected abstract boolean isRoleValid(Cookie cookie);
52
53     @Override
54     public final void init(FilterConfig filterConfig) throws ServletException {
55         filterConfiguration = getFilterConfiguration();
56         excludedUrls = filterConfiguration.getExcludedUrls();
57     }
58
59     @Override
60     public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
61         final HttpServletRequest httpRequest = (HttpServletRequest) servletRequest;
62         final HttpServletResponse httpResponse = (HttpServletResponse) servletResponse;
63
64         long starTime = System.nanoTime();
65         log.debug("SessionValidationFilter: Validation started, received request with URL {}", httpRequest.getRequestURL());
66
67         // request preprocessing
68         boolean isContinueProcessing = preProcessingRequest(servletRequest, servletResponse, filterChain, httpRequest, httpResponse);
69         List<Cookie> cookies = null;
70
71         // request processing
72         if (isContinueProcessing) {
73             cookies = extractAuthenticationCookies(httpRequest.getCookies());
74             isContinueProcessing = processRequest(httpRequest, httpResponse, cookies.get(0));
75         }
76
77         // response processing
78         if(isContinueProcessing){
79             log.debug("SessionValidationFilter: Cookie from request {} is valid, passing request to session extension ...", httpRequest.getRequestURL());
80             Cookie updatedCookie = processResponse(cookies.get(cookies.size()-1));
81
82             cleanResponceFromLeftoverCookies(httpResponse, cookies);
83
84             // Use responce wrapper if servlet remove Cookie header from responce
85 //            OutputStream out = httpResponse.getOutputStream();
86 //            ResponceWrapper responceWrapper = new ResponceWrapper(httpResponse);
87
88             log.debug("SessionValidationFilter: request {} passed all validations, passing request to endpoint ...", httpRequest.getRequestURL());
89             httpResponse.addCookie(updatedCookie);
90             filterChain.doFilter(servletRequest, httpResponse);
91
92             // Use responce wrapper if servlet remove Cookie header from responce
93 //            responceWrapper.addCookie(updatedCookie);
94 //            httpResponse.setContentLength(responceWrapper.getData().length);
95 //            out.write(responceWrapper.getData());
96 //            out.close();
97         }
98         long durationSec = TimeUnit.NANOSECONDS.toSeconds(System.nanoTime() - starTime);
99         long durationMil = TimeUnit.NANOSECONDS.toMillis(System.nanoTime() - starTime);
100         log.debug("SessionValidationFilter: Validation ended, running time for URL {} is: {} seconds {} miliseconds", httpRequest.getPathInfo(), durationSec, durationMil);
101     }
102
103
104     private boolean preProcessingRequest(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain, HttpServletRequest httpRequest, HttpServletResponse httpResponse) throws IOException, ServletException {
105
106         boolean isPreProcessingSucceeded = true;
107         if (isUrlFromWhiteList(httpRequest)) {
108             log.debug("SessionValidationFilter: URL {} excluded from access validation , passing request to endpoint ... ", httpRequest.getRequestURL());
109             filterChain.doFilter(servletRequest, servletResponse);
110             isPreProcessingSucceeded = false;
111
112         } else if (!isCookiePresent(httpRequest.getCookies())) {
113             //redirect to portal app
114             log.debug("SessionValidationFilter: Cookie from request {} is not valid, redirecting request to portal", httpRequest.getRequestURL());
115             httpResponse.sendRedirect(filterConfiguration.getRedirectURL());
116             isPreProcessingSucceeded = false;
117         }
118         return isPreProcessingSucceeded;
119     }
120
121     private boolean processRequest(HttpServletRequest httpRequest, HttpServletResponse httpResponse, Cookie cookie) throws IOException {
122         boolean isProcessSuccessful= true;
123         try {
124             if (AuthenticationCookieUtils.isSessionExpired(cookie, filterConfiguration)) {
125                 //redirect to portal app
126                 log.debug("SessionValidationFilter: Session is expired, redirecting request {} to portal", httpRequest.getRequestURL());
127                 httpResponse.sendRedirect(filterConfiguration.getRedirectURL());
128                 isProcessSuccessful = false;
129             }
130         } catch (CipherUtilException e) {
131             log.error("SessionValidationFilter: Cookie decryption error : {}", e.getMessage());
132             log.debug("SessionValidationFilter: Cookie decryption error : {}", e.getMessage(), e);
133             isProcessSuccessful = false;
134         }
135
136         if (!isRoleValid(cookie)) {
137             //redirect to portal app
138             log.debug("SessionValidationFilter: Role is not valid, redirecting request {} to portal", httpRequest.getRequestURL());
139             httpResponse.sendRedirect(filterConfiguration.getRedirectURL());
140             isProcessSuccessful = false;
141         }
142         return isProcessSuccessful;
143     }
144
145     private Cookie processResponse(Cookie cookie) throws IOException, ServletException {
146         Cookie updatedCookie;
147         try {
148             updatedCookie = AuthenticationCookieUtils.updateSessionTime(cookie, filterConfiguration);
149         } catch (CipherUtilException e) {
150             log.error("SessionValidationFilter: Cookie cipher error ...");
151             log.debug("SessionValidationFilter: Cookie cipher error : {}", e.getMessage(), e);
152             throw new ServletException(e.getMessage());
153         }
154         updatedCookie = addRoleToCookie(updatedCookie);
155         return updatedCookie;
156     }
157
158     private boolean isCookiePresent(Cookie[] cookies) {
159         if (cookies == null) {
160             return false;
161         }
162         String actualCookieName = filterConfiguration.getCookieName();
163         boolean isPresent = Arrays.stream(cookies).anyMatch(c -> isCookieNameMatch(actualCookieName, c));
164         if (!isPresent) {
165             log.error("SessionValidationFilter: Session Validation Cookie missing ...");
166             return false;
167         }
168         return true;
169     }
170
171     private List<Cookie> extractAuthenticationCookies(Cookie[] cookies) {
172         String actualCookieName = filterConfiguration.getCookieName();
173         log.debug("SessionValidationFilter: Extracting authentication cookies, {} cookies in request", cookies.length);
174         List<Cookie> authenticationCookies = Arrays.stream(cookies).filter(c -> isCookieNameMatch(actualCookieName, c)).collect(Collectors.toList());
175         log.debug("SessionValidationFilter: Extracted {} authentication cookies from request", authenticationCookies.size());
176         if( authenticationCookies.size() > 1 ){
177             authenticationCookies.forEach( cookie -> log.debug("SessionValidationFilter: Multiple cookies found cookie name, {} cookie value {}", cookie.getName(), cookie.getValue()));
178         }
179         return authenticationCookies;
180     }
181
182
183     // use contains for matching due issue with ecomp portal ( change cookie name, add prefix ), temp solution
184     private boolean isCookieNameMatch(String actualCookieName, Cookie c) {
185         return c.getName().contains(actualCookieName);
186     }
187
188     private boolean isUrlFromWhiteList(HttpServletRequest httpRequest) {
189         if (httpRequest.getPathInfo() == null){
190             final String servletPath = httpRequest.getServletPath().toLowerCase();
191             log.debug("SessionValidationFilter: pathInfo is null, trying to check by servlet path white list validation -> ServletPath: {} ", servletPath);
192             return excludedUrls.stream().
193                     anyMatch( e -> servletPath.matches(e));
194         }
195         String pathInfo = httpRequest.getPathInfo().toLowerCase();
196         log.debug("SessionValidationFilter: white list validation ->  PathInfo: {} ", pathInfo);
197         return excludedUrls.stream().
198                 anyMatch( e -> pathInfo.matches(e));
199     }
200
201     private void cleanResponceFromLeftoverCookies(HttpServletResponse httpResponse, List<Cookie> cookiesList) {
202         for (Cookie cookie:cookiesList){
203             Cookie cleanCookie = AuthenticationCookieUtils.createUpdatedCookie(cookie, null, filterConfiguration);
204             cleanCookie.setMaxAge(0);
205             log.debug("SessionValidationFilter Cleaning Cookie cookie name: {} added to responce", cleanCookie.getName());
206             httpResponse.addCookie(cleanCookie);
207         }
208     }
209
210     @Override
211     public void destroy() {
212
213     }
214 }