[PORTAL-7] Rebase
[portal.git] / ecomp-portal-BE-common / src / main / java / org / openecomp / portalapp / portal / interceptor / PortalResourceInterceptor.java
1 /*-
2  * ================================================================================
3  * ECOMP Portal
4  * ================================================================================
5  * Copyright (C) 2017 AT&T Intellectual Property
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
10  * 
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  * 
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  * ================================================================================*/
19 package org.openecomp.portalapp.portal.interceptor;
20
21 import java.net.URL;
22 import java.nio.charset.Charset;
23 import java.util.Base64;
24 import java.util.Set;
25
26 import javax.servlet.http.HttpServletRequest;
27 import javax.servlet.http.HttpServletResponse;
28
29 import org.openecomp.portalapp.controller.sessionmgt.SessionCommunicationController;
30 import org.openecomp.portalapp.portal.controller.BasicAuthenticationController;
31 import org.openecomp.portalapp.portal.controller.ExternalAppsRestfulController;
32 import org.openecomp.portalapp.portal.controller.SharedContextRestController;
33 import org.openecomp.portalapp.portal.controller.WebAnalyticsExtAppController;
34 import org.openecomp.portalapp.portal.domain.BasicAuthCredentials;
35 import org.openecomp.portalapp.portal.domain.EPEndpoint;
36 import org.openecomp.portalapp.portal.domain.EPUser;
37 import org.openecomp.portalapp.portal.logging.aop.EPEELFLoggerAdvice;
38 import org.openecomp.portalapp.portal.logging.format.EPAppMessagesEnum;
39 import org.openecomp.portalapp.portal.logging.logic.EPLogUtil;
40 import org.openecomp.portalapp.portal.service.BasicAuthenticationCredentialService;
41 import org.openecomp.portalapp.portal.utils.EcompPortalUtils;
42 import org.openecomp.portalapp.service.RemoteWebServiceCallService;
43 import org.openecomp.portalapp.service.sessionmgt.ManageService;
44 import org.openecomp.portalapp.util.EPUserUtils;
45 import org.openecomp.portalsdk.core.controller.FusionBaseController;
46 import org.openecomp.portalsdk.core.exception.UrlAccessRestrictedException;
47 import org.openecomp.portalsdk.core.interceptor.ResourceInterceptor;
48 import org.openecomp.portalsdk.core.logging.logic.EELFLoggerDelegate;
49 import org.openecomp.portalsdk.core.onboarding.listener.PortalTimeoutHandler;
50 import org.openecomp.portalsdk.core.onboarding.util.CipherUtil;
51 import org.openecomp.portalsdk.core.util.SystemProperties;
52 import org.openecomp.portalsdk.core.util.SystemProperties.SecurityEventTypeEnum;
53 import org.springframework.beans.factory.annotation.Autowired;
54 import org.springframework.web.method.HandlerMethod;
55
56 public class PortalResourceInterceptor extends ResourceInterceptor {
57         private static final String APP_KEY = "uebkey";
58
59         private EELFLoggerDelegate logger = EELFLoggerDelegate.getLogger(PortalResourceInterceptor.class);
60
61         @Autowired
62         private  RemoteWebServiceCallService remoteWebServiceCallService;
63
64         @Autowired
65         private ManageService manageService;
66
67         @Autowired
68         private EPEELFLoggerAdvice epAdvice;
69
70         @Autowired
71         private BasicAuthenticationCredentialService basicAuthService;
72
73         @SuppressWarnings("unchecked")
74         @Override
75         public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
76                         throws Exception {
77
78                 if (handler instanceof HandlerMethod) {
79                         HandlerMethod method = (HandlerMethod) handler;
80
81                         /**
82                          * These classes provide REST endpoints used by other application
83                          * servers, NOT by an end user's browser.
84                          */
85                         if (method.getBean() instanceof FusionBaseController) {
86                                 FusionBaseController controller = (FusionBaseController) method.getBean();
87                                 if (!controller.isAccessible()) {
88
89                                         // authorize portalApi requests by user role
90                                         String requestURI = request.getRequestURI();
91                                         if (requestURI != null) {
92                                                 String[] uriArray = requestURI.split("/portalApi/");
93                                                 if (uriArray.length > 1) {
94                                                         String portalApiPath = uriArray[1];
95
96                                                         Set<? extends String> roleFunctions = (Set<? extends String>) request.getSession()
97                                                                         .getAttribute(SystemProperties
98                                                                                         .getProperty(SystemProperties.ROLE_FUNCTIONS_ATTRIBUTE_NAME));
99                                                         Set<? extends String> allRoleFunctions = (Set<? extends String>) request.getSession()
100                                                                         .getAttribute(EPUserUtils.ALL_ROLE_FUNCTIONS);
101                                                         // Defend against code error to avoid throwing NPE
102                                                         if (roleFunctions == null || allRoleFunctions == null) {
103                                                                 logger.error(EELFLoggerDelegate.errorLogger,
104                                                                                 "preHandle: failed to get role functions attribute(s) from session!!");
105                                                                 EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeInitializationError);
106                                                                 return false;
107                                                         }
108                                                         // check to see if roleFunctions of the user is in
109                                                         // the
110                                                         // list of all role functions
111                                                         // if not, ignore to prevent restricting every
112                                                         // trivial
113                                                         // call; otherwise, if it is, then check for the
114                                                         // access
115                                                         if (matchRoleFunctions(portalApiPath, allRoleFunctions)
116                                                                         && !matchRoleFunctions(portalApiPath, roleFunctions)) {
117                                                                 EPUser user = (EPUser) request.getSession().getAttribute(
118                                                                                 SystemProperties.getProperty(SystemProperties.USER_ATTRIBUTE_NAME));
119                                                                 logger.error(EELFLoggerDelegate.errorLogger,
120                                                                                 "preHandle: User {} not authorized for path {} ", user.getOrgUserId(),
121                                                                                 portalApiPath);
122                                                                 EcompPortalUtils.setBadPermissions(user, response, portalApiPath);
123                                                                 EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeRestApiAuthenticationError);
124                                                                 return false;
125                                                         } // failed to match
126
127                                                 } // is portalApi
128
129                                         } // requestURI
130                                 } // instance check
131                         } // not accessible
132                         else if (method.getBean() instanceof BasicAuthenticationController) {
133                                 return checkBasicAuth(request, response);
134                         }
135                         Object controllerObj = method.getBean();
136                         if (controllerObj instanceof SessionCommunicationController
137                                         || controllerObj instanceof SharedContextRestController
138                                         || controllerObj instanceof ExternalAppsRestfulController) {
139                                 // check user authentication for RESTful calls
140                                 String secretKey = null;
141                                 try {
142                                         epAdvice.loadServletRequestBasedDefaults(request, SecurityEventTypeEnum.INCOMING_REST_MESSAGE);
143                                         if (!remoteWebServiceCallService.verifyRESTCredential(secretKey, request.getHeader(APP_KEY),
144                                                         request.getHeader("username"), request.getHeader("password"))) {
145                                                 throw new UrlAccessRestrictedException();
146                                         }
147                                 } catch (Exception e) {
148                                         logger.error(EELFLoggerDelegate.errorLogger, "preHandle: failed to authenticate RESTful service",
149                                                         e);
150                                         EPLogUtil.logEcompError(logger, EPAppMessagesEnum.BeRestApiAuthenticationError, e);
151                                         throw new UrlAccessRestrictedException();
152                                 }
153                         }
154
155                         if (controllerObj instanceof WebAnalyticsExtAppController) {
156                                 if (!remoteWebServiceCallService.verifyAppKeyCredential(request.getHeader(APP_KEY))) {
157                                         logger.error(EELFLoggerDelegate.errorLogger,
158                                                         "preHandle: failed to verify app key for web analytics call");
159                                         throw new UrlAccessRestrictedException();
160                                 }
161                         }
162                 }
163
164                 handleSessionUpdates(request);
165                 return true;
166         }
167
168         /**
169          * Sets the status code and sends a response. Factors code out of many
170          * methods.
171          * 
172          * @param response
173          *            HttpServletResponse
174          * @param statusCode
175          *            HTTP status code like 404
176          * @param message
177          *            Message to send in a JSON error object
178          */
179         private void sendErrorResponse(HttpServletResponse response, final int statusCode, final String message)
180                         throws Exception {
181                 response.setStatus(statusCode);
182                 response.setContentType("application/json");
183                 response.getWriter().write("{\"error\":\"" + message + "\"}");
184                 response.getWriter().flush();
185         }
186
187         /**
188          * Gets HTTP basic authentication information from the request and checks
189          * whether those credentials are authorized for the request path.
190          * 
191          * @param request
192          *            HttpServletRequest
193          * @param response
194          *            HttpServletResponse
195          * @return True if the request is authorized, else false
196          * @throws Exception
197          */
198         private boolean checkBasicAuth(HttpServletRequest request, HttpServletResponse response) throws Exception {
199                 
200                 String uri = request.getRequestURI().toString();
201                 uri = uri.substring(uri.indexOf("/", 1));
202                 
203                 final String authHeader = request.getHeader("Authorization");
204                 if (authHeader == null) {
205                         final String msg = "no authorization found";
206                         logger.debug(EELFLoggerDelegate.debugLogger, "checkBasicAuth: {}", msg);
207                         sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, msg);
208                         return false;
209                 }
210
211                 String[] accountNamePassword = getUserNamePassword(authHeader);
212                 if (accountNamePassword == null || accountNamePassword.length != 2) {
213                         final String msg = "failed to get username and password from auth header";
214                         logger.debug(EELFLoggerDelegate.debugLogger, "checkBasicAuth: {}", msg);
215                         sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, msg);
216                         return false;
217                 }
218
219                 BasicAuthCredentials creds;
220                 try {
221                         creds = basicAuthService.getBasicAuthCredentialByAppName(accountNamePassword[0]);
222                 } catch (Exception e) {
223                         logger.error(EELFLoggerDelegate.errorLogger, "checkBasicAuth failed to get credentials", e);
224                         final String msg = "Failed while getting basic authentication credential: " + e.toString();
225                         sendErrorResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
226                         throw e;
227                 }
228                 
229                 boolean isAllowedEp = false;
230                 for(EPEndpoint ep: creds.getEndpoints()){
231                         if(ep.getName().equals(uri)){
232                                 isAllowedEp = true;
233                                 break;
234                         }
235                 }
236                 if(!isAllowedEp){
237                         response.setStatus(401);
238                         response.setContentType("application/json");
239                         response.getWriter().write("{\"error\":\"Unauthorized: Endpoint access denied\"}");
240                         response.getWriter().flush();
241                         response.getWriter().close();
242                         return false;
243                 }
244                 
245                 if (creds == null) {
246                         final String msg = "failed to find match for credentials";
247                         logger.debug(EELFLoggerDelegate.debugLogger, "checkBasicAuth: {}", msg);
248                         sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, msg);
249                         return false;
250                 }
251
252                 boolean isAuth;
253                 try {
254                         isAuth = authorization(authHeader, creds.getApplicationName(), creds.getPassword());
255                 } catch (Exception e) {
256                         logger.error(EELFLoggerDelegate.errorLogger, "checkBasicAuth failed to check authorization", e);
257                         final String msg = "failed while checking authorization: " + e.toString();
258                         sendErrorResponse(response, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg);
259                         throw e;
260                 }
261
262                 if (!isAuth) {
263                         response.setStatus(401);
264                         response.setContentType("application/json");
265                         response.getWriter().write("{\"error\":\"Unauthorized: Invalid username or password\"}");
266                         response.getWriter().flush();
267                         response.getWriter().close();
268                         final String msg = "Unauthorized: Access denied";
269                         sendErrorResponse(response, HttpServletResponse.SC_UNAUTHORIZED, msg);
270                         return false;
271                 }
272
273                 // Made it to the end!
274                 return true;
275         }
276
277         /**
278          * 
279          * Basic Authorization check
280          * 
281          * @param auth
282          * @param security_user
283          * @param security_pass
284          * @return
285          * @throws Exception
286          */
287
288         protected boolean authorization(String auth, String security_user, String security_pass) throws Exception {
289
290                 if (auth != null && auth.startsWith("Basic")) {
291                         String[] usernamePassword = getUserNamePassword(auth);
292                         if (security_user.equals(usernamePassword[0]) && decrypted(security_pass).equals(usernamePassword[1]))
293                                 return true;
294                 }
295                 return false;
296         }
297
298         public static void main(String str[]) {
299                 System.out.println(new PortalResourceInterceptor().getUserNamePassword("Basic Qy1CVVM6X3Bhc3M=")[0]);
300                 System.out.println(new PortalResourceInterceptor().getUserNamePassword("Basic Qy1CVVM6X3Bhc3M=")[1]);
301         }
302
303         private String[] getUserNamePassword(String authValue) {
304                 String base64Credentials = authValue.substring("Basic".length()).trim();
305                 String credentials = new String(Base64.getDecoder().decode(base64Credentials), Charset.forName("UTF-8"));
306                 final String[] values = credentials.split(":", 2);
307                 return values;
308         }
309
310         private String decrypted(String encrypted) throws Exception {
311                 String result = "";
312                 if (encrypted != null & encrypted.length() > 0) {
313                         try {
314                                 result = CipherUtil.decrypt(encrypted, SystemProperties.getProperty(SystemProperties.Decryption_Key));
315                         } catch (Exception e) {
316                                 logger.error(EELFLoggerDelegate.errorLogger, "decryptedPassword failed", e);
317                                 throw e;
318                         }
319                 }
320                 return result;
321         }
322
323         private Boolean matchRoleFunctions(String portalApiPath, Set<? extends String> roleFunctions) {
324                 for (String roleFunction : roleFunctions) {
325                         if (portalApiPath.matches(roleFunction))
326                                 return true;
327                 }
328                 return false;
329
330         }
331
332         protected void handleSessionUpdates(HttpServletRequest request) {
333                 PortalTimeoutHandler.handleSessionUpdatesNative(request, null, null, null, null, manageService);
334         }
335 }