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