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=========================================================
21 package org.openecomp.sdc.securityutil.filters;
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;
30 import org.apache.commons.lang.StringUtils;
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;
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;
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";
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";
66 public abstract ISessionValidationFilterConfiguration getFilterConfiguration();
67 protected abstract Cookie addRoleToCookie(Cookie updatedCookie);
68 protected abstract boolean isRoleValid(Cookie cookie);
71 public final void init(FilterConfig filterConfig) throws ServletException {
72 filterConfiguration = getFilterConfiguration();
73 excludedUrls = filterConfiguration.getExcludedUrls();
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;
81 long startTime = System.nanoTime();
82 fillMDCFromHeaders(httpRequest);
83 log.debug("SessionValidationFilter: Validation started, received request with URL {}", httpRequest.getRequestURL());
85 // request preprocessing
86 boolean isContinueProcessing = preProcessingRequest(servletRequest, servletResponse, filterChain, httpRequest, httpResponse, startTime);
87 List<Cookie> cookies = null;
88 Cookie extractedCookie = null;
91 if (isContinueProcessing) {
92 cookies = extractAuthenticationCookies(httpRequest.getCookies());
93 extractedCookie = cookies.get(0);
94 isContinueProcessing = processRequest(httpRequest, httpResponse, extractedCookie);
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);
112 private boolean preProcessingRequest(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain, HttpServletRequest httpRequest, HttpServletResponse httpResponse, long startTime) throws IOException, ServletException {
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;
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;
129 return isPreProcessingSucceeded;
132 private boolean processRequest(HttpServletRequest httpRequest, HttpServletResponse httpResponse, Cookie cookie) throws IOException {
133 boolean isProcessSuccessful= true;
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;
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;
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;
153 return isProcessSuccessful;
156 private Cookie processResponse(Cookie cookie) throws IOException, ServletException {
157 Cookie updatedCookie;
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());
165 updatedCookie = addRoleToCookie(updatedCookie);
166 return updatedCookie;
169 private boolean isCookiePresent(Cookie[] cookies) {
170 if (cookies == null) {
173 String actualCookieName = filterConfiguration.getCookieName();
174 boolean isPresent = Arrays.stream(cookies).anyMatch(c -> isCookieNameMatch(actualCookieName, c));
176 log.error("SessionValidationFilter: Session Validation Cookie missing ...");
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()));
190 return authenticationCookies;
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);
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));
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));
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);
221 public static void fillMDCFromHeaders(HttpServletRequest httpServletRequest) {
222 fillRequestIdFromHeader(httpServletRequest);
223 fillPartnerNameFromHeader(httpServletRequest);
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));
238 MDC.put(REQUEST_ID, UUID.randomUUID().toString());
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));
252 MDC.put(PARTNER_NAME, UNKNOWN);
259 public void destroy() {