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