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