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