1f06f9d4be76122462db19f758bbb9793ebb469e
[aai/sparky-be.git] / src / main / java / org / openecomp / sparky / security / filter / CspCookieFilter.java
1 /**
2  * ============LICENSE_START=======================================================
3  * org.onap.aai
4  * ================================================================================
5  * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6  * Copyright © 2017 Amdocs
7  * ================================================================================
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  *       http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  * ============LICENSE_END=========================================================
20  *
21  * ECOMP is a trademark and service mark of AT&T Intellectual Property.
22  */
23 package org.openecomp.sparky.security.filter;
24
25 import java.io.FileInputStream;
26 import java.io.IOException;
27 import java.io.InputStream;
28 import java.io.UnsupportedEncodingException;
29 import java.net.InetAddress;
30 import java.net.URLDecoder;
31 import java.net.URLEncoder;
32 import java.net.UnknownHostException;
33 import java.nio.charset.StandardCharsets;
34 import java.util.ArrayList;
35 import java.util.Arrays;
36 import java.util.List;
37 import java.util.Properties;
38
39 import javax.servlet.Filter;
40 import javax.servlet.FilterChain;
41 import javax.servlet.FilterConfig;
42 import javax.servlet.ServletException;
43 import javax.servlet.ServletRequest;
44 import javax.servlet.ServletResponse;
45 import javax.servlet.http.Cookie;
46 import javax.servlet.http.HttpServletRequest;
47 import javax.servlet.http.HttpServletResponse;
48
49 import org.openecomp.cl.api.Logger;
50 import org.openecomp.cl.eelf.LoggerFactory;
51 import org.openecomp.sparky.logging.AaiUiMsgs;
52 import org.openecomp.sparky.util.NodeUtils;
53 import org.openecomp.sparky.viewandinspect.config.TierSupportUiConstants;
54
55 import org.openecomp.cl.mdc.MdcContext;
56
57 // import esGateKeeper.esGateKeeper;
58
59 /**
60  * Redirects to the AT&T global login page if the user is not authenticated.<br>
61  * Filter properties need to be configured in: csp-cookie-filter.properties
62  */
63 public class CspCookieFilter implements Filter {
64
65   /** Redirect URL for the login page. */
66   private String globalLoginUrl;
67
68   /** Application identifier. */
69   private String applicationId;
70
71   /** Gatekeeper environment setting (development or production). */
72   private String gateKeeperEnvironment;
73
74   private static final String FILTER_PARAMETER_CONFIG = "config";
75   private static final String PROPERTY_GLOBAL_LOGIN_URL = "global.login.url";
76   private static final String PROPERTY_APPLICATION_ID = "application.id";
77   private static final String PROPERTY_GATEKEEPER_ENVIRONMENT = "gatekeeper.environment";
78   // valid open redirect domains
79   private List<String> redirectDomains = new ArrayList<>();
80   private static final String PROPERTY_REDIRECT_DOMAINS = "redirect-domain";
81
82   /** Needed by esGateKeeper, does not accept any other value. */
83   private static final String GATEKEEPER_ACCOUNT_NAME = "CSP";
84
85   private static final Logger LOG = LoggerFactory.getInstance().getLogger(CspCookieFilter.class);
86
87
88   /* (non-Javadoc)
89    * @see javax.servlet.Filter#init(javax.servlet.FilterConfig)
90    */
91   @Override
92   public void init(FilterConfig filterConfig) throws ServletException {
93         String txnID = NodeUtils.getRandomTxnId();
94         MdcContext.initialize(txnID, "CspCookieFilter", "", "Init", "");
95         
96         try {
97       setConfigurationProperties(filterConfig);
98     } catch (IOException exc) {
99       LOG.error(AaiUiMsgs.ERROR_CSP_CONFIG_FILE);
100       throw new ServletException(exc);
101     }
102   }
103
104
105   /* (non-Javadoc)
106    * @see javax.servlet.Filter#doFilter(javax.servlet.ServletRequest, javax.servlet.ServletResponse, javax.servlet.FilterChain)
107    */
108   @Override
109   public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
110       throws IOException, ServletException {
111     HttpServletRequest request = (HttpServletRequest) req;
112     HttpServletResponse response = (HttpServletResponse) res;
113
114     Cookie[] cookies = request.getCookies();
115     if ((cookies == null) || (cookies.length == 0)) {
116       doLogin(request, response);
117       return;
118     }
119
120     /*
121      * String attEsSec = getSecurityCookie(cookies);
122      * 
123      * if (attESSec == null || attESSec.length() == 0) { doLogin(request, response); return; }
124      * 
125      * String attESSecUnEncrypted = esGateKeeper.esGateKeeper(attESSec, GATEKEEPER_ACCOUNT_NAME,
126      * gateKeeperEnvironment); if (attESSecUnEncrypted == null) { doLogin(request, response); } else
127      * {
128      */
129     // LOG.info("User has valid cookie");
130     chain.doFilter(request, response);
131     // }
132   }
133
134
135   /* (non-Javadoc)
136    * @see javax.servlet.Filter#destroy()
137    */
138   @Override
139   public void destroy() {}
140
141   /**
142    * Sets all required properties needed by this filter.
143    *
144    * @param filterConfig the filter configuration defined in the application web.xml
145    * @throws IOException if the properties failed to load.
146    */
147   private void setConfigurationProperties(FilterConfig filterConfig) throws IOException {
148     InputStream inputStream = new FileInputStream(TierSupportUiConstants.STATIC_CONFIG_APP_LOCATION
149         + filterConfig.getInitParameter(FILTER_PARAMETER_CONFIG));
150     Properties cspProperties = new Properties();
151     cspProperties.load(inputStream);
152     globalLoginUrl = cspProperties.getProperty(PROPERTY_GLOBAL_LOGIN_URL);
153     applicationId = cspProperties.getProperty(PROPERTY_APPLICATION_ID);
154     gateKeeperEnvironment = cspProperties.getProperty(PROPERTY_GATEKEEPER_ENVIRONMENT);
155     redirectDomains = Arrays.asList(cspProperties.getProperty(PROPERTY_REDIRECT_DOMAINS).split(","));
156   }
157
158   /**
159    * Returns the attESSec cookie if found in the client.
160    *
161    * @param cookies the cookies available in the client
162    * @return the attESSec authentication cookie generated by the login page.
163    */
164   private String getSecurityCookie(Cookie[] cookies) {
165     String attEsSec = null;
166     for (int i = 0; i < cookies.length; i++) {
167       Cookie thisCookie = cookies[i];
168       String cookieName = thisCookie.getName();
169
170       if ("attESSec".equals(cookieName)) {
171         attEsSec = thisCookie.getValue();
172         break;
173       }
174     }
175     return attEsSec;
176   }
177
178   /**
179    * Redirects to the AT&T global login page. If this is an AJAX request it returns an unauthorized
180    * HTTP error in the response.
181    *
182    * @param request the filter request object
183    * @param response the filter response object
184    * @throws IOException if there is an error setting the error response
185    */
186   private void doLogin(HttpServletRequest request, HttpServletResponse response)
187       throws IOException {
188     if (isAjaxRequest(request)) {
189       response.sendError(HttpServletResponse.SC_UNAUTHORIZED,
190           "User is not authorized. Please login to application");
191     } else {
192       // Fix for Safari 7.0.2 onwards to avoid login page cache
193       response.addHeader("Cache-Control", "no-cache, no-store");
194       String redirectURL = createRedirectUrl(request);
195       if (this.isValidRedirectURL(redirectURL)){
196           response.sendRedirect(redirectURL);
197           LOG.debug(AaiUiMsgs.VALID_REDIRECT_URL, redirectURL);
198       } else{ 
199           response.sendError(400, "Bad redirect URL: " + redirectURL);
200           LOG.error(AaiUiMsgs.INVALID_REDIRECT_URL, redirectURL);
201       }
202     }
203   }
204   
205   /**
206    * Checks if a redirect url is valid
207    * @param url URL to validate
208    * @return true if URL is a valid redirect URL, false otherwise
209    */
210   private boolean isValidRedirectURL (String url){
211       String redirectTo = url.substring(url.indexOf("?retURL=")+ "?retURL=".length());
212       try {
213           redirectTo = URLDecoder.decode(redirectTo, StandardCharsets.UTF_8.toString());
214       } catch (UnsupportedEncodingException e) {
215           LOG.error(AaiUiMsgs.UNSUPPORTED_URL_ENCODING, e.getLocalizedMessage());
216           return false;
217       }
218       for (String domain: this.redirectDomains){
219           if (redirectTo.endsWith(domain))
220               return true;
221       }
222       return false;
223   }
224   
225
226   /**
227    * Returns <code>true</code> if the request is an AJAX request.
228    *
229    * @param request the filter request object
230    * @return <code>true</code> if the request is an AJAX request.
231    */
232   private boolean isAjaxRequest(HttpServletRequest request) {
233     String headerValue = request.getHeader("X-Requested-With");
234     if ("XMLHttpRequest".equals(headerValue)) {
235       return true;
236     }
237     return false;
238   }
239
240   /**
241    * Returns the redirection URL to the AT&T Global login page.
242    *
243    * @param request the request
244    * @return the string
245    * @throws UnsupportedEncodingException the unsupported encoding exception
246    */
247   private String createRedirectUrl(HttpServletRequest request) throws UnsupportedEncodingException {
248     String returnUrl = getReturnUrl(request);
249
250     return globalLoginUrl + "?retURL=" + returnUrl + "&sysName=" + applicationId;
251   }
252
253   /**
254    * Gets the URL encoded return URL.
255    *
256    * @param request the HTTP request
257    * @return an encoded URL to return to following login
258    * @throws UnsupportedEncodingException the unsupported encoding exception
259    */
260   private String getReturnUrl(HttpServletRequest request) throws UnsupportedEncodingException {
261     StringBuffer retUrl = request.getRequestURL();
262     String urlParams = request.getQueryString();
263     if (urlParams != null) {
264       retUrl.append("?" + urlParams);
265     }
266     return URLEncoder.encode(retUrl.toString(), StandardCharsets.UTF_8.toString());
267   }
268 }