2 * ================================================================================
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
11 * http://www.apache.org/licenses/LICENSE-2.0
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 * ================================================================================
20 package org.openecomp.portalsdk.core.onboarding.crossapi;
22 import java.io.BufferedReader;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.InputStreamReader;
26 import java.io.PrintWriter;
27 import java.io.StringWriter;
28 import java.util.List;
31 import javax.servlet.ServletException;
32 import javax.servlet.annotation.WebServlet;
33 import javax.servlet.http.HttpServlet;
34 import javax.servlet.http.HttpServletRequest;
35 import javax.servlet.http.HttpServletResponse;
37 import org.apache.commons.logging.Log;
38 import org.apache.commons.logging.LogFactory;
39 import org.openecomp.portalsdk.core.onboarding.exception.PortalAPIException;
40 import org.openecomp.portalsdk.core.onboarding.listener.PortalTimeoutHandler;
41 import org.openecomp.portalsdk.core.onboarding.rest.RestWebServiceClient;
42 import org.openecomp.portalsdk.core.onboarding.util.PortalApiConstants;
43 import org.openecomp.portalsdk.core.onboarding.util.PortalApiProperties;
44 import org.openecomp.portalsdk.core.restful.domain.EcompRole;
45 import org.openecomp.portalsdk.core.restful.domain.EcompUser;
47 import com.fasterxml.jackson.core.JsonProcessingException;
48 import com.fasterxml.jackson.core.type.TypeReference;
49 import com.fasterxml.jackson.databind.DeserializationFeature;
50 import com.fasterxml.jackson.databind.ObjectMapper;
53 * This servlet performs the functions described below. It listens on a path
54 * like "/api" (see {@link PortalApiConstants#API_PREFIX}). The servlet checks
55 * for authorized access and rejects unauthorized requests.
57 * <LI>Proxies user (i.e., browser) requests for web analytics. The GET method
58 * fetches javascript from the Portal and returns it. The POST method forwards
59 * data sent by the browser on to Portal. These requests are checked for a valid
60 * User UID in a header; these requests do NOT use the application
61 * username-password header.</LI>
62 * <LI>Responds to ECOMP Portal API requests to query and update user, role and
63 * user-role information. The servlet proxies all requests on to a local Java
64 * class that implements {@link IPortalRestAPIService}. These requests must have
65 * the application username-password header.</LI>
67 * This servlet will not start if the required portal.properties file is not
68 * found on the classpath.
71 @WebServlet(urlPatterns = { PortalApiConstants.API_PREFIX + "/*" })
72 public class PortalRestAPIProxy extends HttpServlet implements IPortalRestAPIService {
73 private static final long serialVersionUID = 1L;
75 private static final String contentTypeAppJson = "application/json";
77 private final Log logger = LogFactory.getLog(getClass());
80 * Mapper for JSON to object etc.
82 private final ObjectMapper mapper = new ObjectMapper();
85 * Client-supplied class that implements our interface.
87 private static IPortalRestAPIService portalRestApiServiceImpl;
89 public PortalRestAPIProxy() {
90 // Ensure that any additional fields sent by the Portal
91 // will be ignored when creating objects.
92 mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
96 public void init() throws ServletException {
97 String className = PortalApiProperties.getProperty(PortalApiConstants.PORTAL_API_IMPL_CLASS);
98 if (className == null)
99 throw new ServletException(
100 "init: Failed to find class name property " + PortalApiConstants.PORTAL_API_IMPL_CLASS);
102 logger.debug("init: creating instance of class " + className);
103 Class<?> implClass = Class.forName(className);
104 portalRestApiServiceImpl = (IPortalRestAPIService) (implClass.getConstructor().newInstance());
105 } catch (Exception ex) {
106 throw new ServletException("init: Failed to find or instantiate class " + className, ex);
111 protected void doPost(HttpServletRequest request, HttpServletResponse response)
112 throws IOException, ServletException {
113 if (portalRestApiServiceImpl == null) {
114 // Should never happen due to checks in init()
115 logger.error("doPost: no service class instance");
116 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
117 response.getWriter().write(buildJsonResponse(false, "Misconfigured - no instance of service class"));
120 String requestUri = request.getRequestURI();
121 String responseJson = "";
122 String storeAnalyticsContextPath = "/storeAnalytics";
123 if (requestUri.endsWith(PortalApiConstants.API_PREFIX + storeAnalyticsContextPath)) {
126 userId = getUserId(request);
127 } catch (PortalAPIException e) {
128 logger.error("Issue with invoking getUserId implemenation !!! ", e);
129 throw new ServletException(e);
131 if (userId == null || userId.length() == 0) {
132 logger.debug("doPost: userId is null or empty");
133 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
134 responseJson = buildJsonResponse(false, "Not authorized for " + storeAnalyticsContextPath);
136 // User ID obtained from request
138 String credential = PortalApiProperties.getProperty(PortalApiConstants.UEB_APP_KEY);
139 // for now lets also pass uebkey as user name and password
140 String requestBody = readRequestBody(request);
141 @SuppressWarnings("unchecked")
142 Map<String, String> bodyMap = mapper.readValue(requestBody, Map.class);
144 bodyMap.put("userid", userId);
145 requestBody = mapper.writeValueAsString(bodyMap);
146 responseJson = RestWebServiceClient.getInstance().postPortalContent(storeAnalyticsContextPath,
147 userId, credential, null, credential, credential, "application/json", requestBody, true);
148 if (logger.isDebugEnabled())
149 logger.debug("doPost: postPortalContent returns " + responseJson);
150 response.setStatus(HttpServletResponse.SC_OK);
151 } catch (Exception ex) {
152 logger.error("doPost: " + storeAnalyticsContextPath + " caught exception", ex);
153 responseJson = buildJsonResponse(ex);
154 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
157 writeAndFlush(response, contentTypeAppJson, responseJson);
161 boolean secure = false;
163 secure = isAppAuthenticated(request);
164 } catch (PortalAPIException ex) {
165 logger.error("doPost: isAppAuthenticated threw exception", ex);
166 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
167 response.getWriter().write(buildJsonResponse(false, "Failed to authenticate request"));
171 if (logger.isDebugEnabled())
172 logger.debug("doPost: isAppAuthenticated answered false");
173 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
174 writeAndFlush(response, contentTypeAppJson, buildJsonResponse(false, "Not authorized"));
179 String requestBody = readRequestBody(request);
180 if (logger.isDebugEnabled())
181 logger.debug("doPost: URI = " + requestUri + ", payload = " + requestBody);
186 * 1. /user <-- save user
188 * 2. /user/{loginId} <-- edit user
190 * 3. /user/{loginId}/roles <-- save roles for user
193 // On success return the empty string.
195 if (requestUri.endsWith("/updateSessionTimeOuts")) {
196 if (updateSessionTimeOuts(requestBody)) {
197 if (logger.isDebugEnabled())
198 logger.debug("doPost: updated session timeouts");
199 response.setStatus(HttpServletResponse.SC_OK);
201 String msg = "Failed to update session time outs";
202 logger.error("doPost: " + msg);
203 responseJson = buildJsonResponse(false, msg);
204 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
206 } else if (requestUri.endsWith("/timeoutSession")) {
207 String portalJSessionId = request.getParameter("portalJSessionId");
208 if (portalJSessionId == null) {
209 portalJSessionId = "";
211 if (timeoutSession(portalJSessionId)) {
212 if (logger.isDebugEnabled())
213 logger.debug("doPost: timed out session");
214 response.setStatus(HttpServletResponse.SC_OK);
216 String msg = "Failed to timeout session";
217 logger.error("doPost: " + msg);
218 responseJson = buildJsonResponse(false, msg);
219 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
222 // Example: /user <-- create user
223 if (requestUri.endsWith(PortalApiConstants.API_PREFIX + "/user")) {
225 EcompUser user = mapper.readValue(requestBody, EcompUser.class);
227 if (logger.isDebugEnabled())
228 logger.debug("doPost: pushUser: success");
229 responseJson = buildJsonResponse(true, null);
230 response.setStatus(HttpServletResponse.SC_OK);
231 } catch (Exception ex) {
232 responseJson = buildJsonResponse(ex);
233 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
234 logger.error("doPost: pushUser: caught exception", ex);
237 // Example: /user/fi241c <-- edit user fi241c
238 if (requestUri.contains(PortalApiConstants.API_PREFIX + "/user/") && !(requestUri.endsWith("/roles"))) {
239 String loginId = requestUri.substring(requestUri.lastIndexOf('/') + 1);
241 EcompUser user = mapper.readValue(requestBody, EcompUser.class);
242 editUser(loginId, user);
243 if (logger.isDebugEnabled())
244 logger.debug("doPost: editUser: success");
245 responseJson = buildJsonResponse(true, null);
246 response.setStatus(HttpServletResponse.SC_OK);
247 } catch (Exception ex) {
248 responseJson = buildJsonResponse(ex);
249 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
250 logger.error("doPost: editUser: caught exception", ex);
253 // Example: /user/{loginId}/roles <-- save roles for user
254 if (requestUri.contains(PortalApiConstants.API_PREFIX + "/user/") && requestUri.endsWith("/roles")) {
255 String loginId = requestUri.substring(requestUri.indexOf("/user/") + ("/user").length() + 1,
256 requestUri.lastIndexOf('/'));
258 TypeReference<List<EcompRole>> typeRef = new TypeReference<List<EcompRole>>() {
260 List<EcompRole> roles = mapper.readValue(requestBody, typeRef);
261 pushUserRole(loginId, roles);
262 if (logger.isDebugEnabled())
263 logger.debug("doPost: pushUserRole: success");
264 responseJson = buildJsonResponse(true, null);
265 response.setStatus(HttpServletResponse.SC_OK);
266 } catch (Exception ex) {
267 responseJson = buildJsonResponse(ex);
268 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
269 logger.error("doPost: pushUserRole: caught exception", ex);
272 String msg = "doPost: no match for request " + requestUri;
274 responseJson = buildJsonResponse(false, msg);
275 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
277 } catch (Exception ex) {
278 logger.error("doPost: Failed to process request " + requestUri, ex);
279 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
280 responseJson = buildJsonResponse(ex);
283 writeAndFlush(response, contentTypeAppJson, responseJson);
288 protected void doGet(HttpServletRequest request, HttpServletResponse response)
289 throws IOException, ServletException {
291 if (portalRestApiServiceImpl == null) {
292 // Should never happen due to checks in init()
293 logger.error("doGet: no service class instance");
294 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
295 writeAndFlush(response, contentTypeAppJson,
296 buildJsonResponse(false, "Misconfigured - no instance of service class"));
300 String requestUri = request.getRequestURI();
301 String responseString = "";
302 String contentType = contentTypeAppJson;
304 String webAnalyticsContextPath = "/analytics";
305 if (requestUri.endsWith(PortalApiConstants.API_PREFIX + webAnalyticsContextPath)) {
308 userId = getUserId(request);
309 } catch (PortalAPIException e) {
310 logger.error("Issue with invoking getUserId implemenation !!! ", e);
311 throw new ServletException(e);
313 if (userId == null || userId.length() == 0) {
314 logger.debug("doGet: userId is null or empty");
315 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
316 responseString = buildJsonResponse(false, "Not authorized for " + webAnalyticsContextPath);
318 // User ID obtained from request
320 String credential = PortalApiProperties.getProperty(PortalApiConstants.UEB_APP_KEY);
321 // for now lets also pass uebkey as user name and password
322 contentType = "text/javascript";
324 responseString = RestWebServiceClient.getInstance().getPortalContent(webAnalyticsContextPath,
325 userId, credential, null, credential, credential,true);
326 if (logger.isDebugEnabled())
327 logger.debug("doGet: " + webAnalyticsContextPath + ": " + responseString);
328 response.setStatus(HttpServletResponse.SC_OK);
329 } catch (Exception ex) {
330 responseString = buildJsonResponse(ex);
331 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
332 logger.error("doGet: " + webAnalyticsContextPath + " caught exception", ex);
335 writeAndFlush(response, contentType, responseString);
339 boolean secure = false;
341 secure = isAppAuthenticated(request);
342 } catch (PortalAPIException ex) {
343 logger.error("doGet: isAppAuthenticated threw exception", ex);
344 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
345 writeAndFlush(response, contentTypeAppJson, buildJsonResponse(false, "Failed to authenticate request"));
350 if (logger.isDebugEnabled())
351 logger.debug("doGet: isAppAuthenticated answered false");
352 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
353 writeAndFlush(response, contentTypeAppJson, buildJsonResponse(false, "Not authorized"));
357 String responseJson = null;
359 // Ignore any request body in a GET.
360 // String requestBody = readRequestBody(request);
361 if (logger.isDebugEnabled())
362 logger.debug("doGet: URI = " + requestUri);
365 * 1. /roles <-- get roles
367 * 2. /user/{loginId} <-- get user
369 * 3. /users <-- get all users
371 * 4. /user/{loginId}/roles <-- get roles for user
374 if (requestUri.endsWith("/sessionTimeOuts")) {
375 responseJson = getSessionTimeOuts();
376 if (responseJson != null && responseJson.length() > 0) {
377 if (logger.isDebugEnabled())
378 logger.debug("doGet: got session timeouts");
379 response.setStatus(HttpServletResponse.SC_OK);
381 String msg = "Failed to get session time outs";
382 logger.error("doGet: " + msg);
383 responseJson = buildJsonResponse(false, msg);
384 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
387 // Example: /users <-- get all users
388 if (requestUri.endsWith(PortalApiConstants.API_PREFIX + "/users")) {
390 List<EcompUser> users = getUsers();
391 responseJson = mapper.writeValueAsString(users);
392 if (logger.isDebugEnabled())
393 logger.debug("doGet: getUsers: " + responseJson);
394 } catch (Exception ex) {
395 responseJson = buildJsonResponse(ex);
396 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
397 logger.error("doGet: getUsers: caught exception", ex);
400 // Example: /roles <-- get all roles
402 if (requestUri.endsWith(PortalApiConstants.API_PREFIX + "/roles")) {
404 List<EcompRole> roles = getAvailableRoles(getUserId(request));
405 responseJson = mapper.writeValueAsString(roles);
406 if (logger.isDebugEnabled())
407 logger.debug("doGet: getAvailableRoles: " + responseJson);
408 } catch (Exception ex) {
409 responseJson = buildJsonResponse(ex);
410 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
411 logger.error("doGet: getAvailableRoles: caught exception", ex);
414 // Example: /user/fi241c <-- get user fi241c
415 if (requestUri.contains(PortalApiConstants.API_PREFIX + "/user/") && !requestUri.endsWith("/roles")) {
416 String loginId = requestUri.substring(requestUri.lastIndexOf('/') + 1);
418 EcompUser user = getUser(loginId);
419 responseJson = mapper.writeValueAsString(user);
420 if (logger.isDebugEnabled())
421 logger.debug("doGet: getUser: " + responseJson);
422 } catch (Exception ex) {
423 responseJson = buildJsonResponse(ex);
424 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
425 logger.error("doGet: getUser: caught exception", ex);
428 // Example: /user/fi241c/roles <-- get roles for user fi241c
429 else if (requestUri.contains(PortalApiConstants.API_PREFIX + "/user/") && requestUri.endsWith("/roles")) {
430 String loginId = requestUri.substring(requestUri.indexOf("/user/") + ("/user").length() + 1,
431 requestUri.lastIndexOf('/'));
433 List<EcompRole> roles = getUserRoles(loginId);
434 responseJson = mapper.writeValueAsString(roles);
435 if (logger.isDebugEnabled())
436 logger.debug("doGet: getUserRoles: " + responseJson);
437 } catch (Exception ex) {
438 responseJson = buildJsonResponse(ex);
439 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
440 logger.error("doGet: getUserRoles: caught exception", ex);
443 logger.warn("doGet: no match found for request");
444 responseJson = buildJsonResponse(false, "No match for request");
445 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
447 } catch (Exception ex) {
448 logger.error("doGet: Failed to process request", ex);
449 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
450 responseJson = buildJsonResponse(ex);
452 writeAndFlush(response, contentTypeAppJson, responseJson);
455 public String getSessionTimeOuts() throws Exception {
456 return PortalTimeoutHandler.gatherSessionExtensions();
459 public boolean timeoutSession(String portalJSessionId) throws Exception {
460 return PortalTimeoutHandler.invalidateSession(portalJSessionId);
463 public boolean updateSessionTimeOuts(String sessionMap) throws Exception {
464 return PortalTimeoutHandler.updateSessionExtensions(sessionMap);
468 public void pushUser(EcompUser user) throws PortalAPIException {
469 portalRestApiServiceImpl.pushUser(user);
473 public void editUser(String loginId, EcompUser user) throws PortalAPIException {
474 portalRestApiServiceImpl.editUser(loginId, user);
478 public EcompUser getUser(String loginId) throws PortalAPIException {
479 return portalRestApiServiceImpl.getUser(loginId);
483 public List<EcompUser> getUsers() throws PortalAPIException {
484 return portalRestApiServiceImpl.getUsers();
488 public List<EcompRole> getAvailableRoles(String requestedLoginId) throws PortalAPIException {
489 return portalRestApiServiceImpl.getAvailableRoles(requestedLoginId);
493 public void pushUserRole(String loginId, List<EcompRole> roles) throws PortalAPIException {
494 portalRestApiServiceImpl.pushUserRole(loginId, roles);
498 public List<EcompRole> getUserRoles(String loginId) throws PortalAPIException {
499 return portalRestApiServiceImpl.getUserRoles(loginId);
503 public boolean isAppAuthenticated(HttpServletRequest request) throws PortalAPIException {
504 return portalRestApiServiceImpl.isAppAuthenticated(request);
508 * Sets the content type and writes the response.
512 * @param responseBody
513 * @throws IOException
515 private void writeAndFlush(HttpServletResponse response, String contentType, String responseBody)
517 response.setContentType(contentType);
518 PrintWriter out = response.getWriter();
519 out.print(responseBody);
524 * Reads the request body and closes the input stream.
527 * @return String read from the request, the empty string if nothing is
529 * @throws IOException
531 private static String readRequestBody(HttpServletRequest request) throws IOException {
534 StringBuilder stringBuilder = new StringBuilder();
535 BufferedReader bufferedReader = null;
537 InputStream inputStream = request.getInputStream();
538 if (inputStream != null) {
539 bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
540 char[] charBuffer = new char[1024];
542 while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
543 stringBuilder.append(charBuffer, 0, bytesRead);
546 stringBuilder.append("");
549 if (bufferedReader != null) {
551 bufferedReader.close();
552 } catch (IOException ex) {
557 body = stringBuilder.toString();
562 * Builds JSON object with status + message response body.
565 * True to indicate success, false to signal failure.
567 * Message to include in the response object; ignored if null.
571 * { "status" : "ok" (or "error"), "message": "some explanation" }
574 private String buildJsonResponse(boolean success, String msg) {
575 PortalAPIResponse response = new PortalAPIResponse(success, msg);
578 json = mapper.writeValueAsString(response);
579 } catch (JsonProcessingException ex) {
580 // Truly should never, ever happen
581 json = "{ \"status\": \"error\",\"message\":\"" + ex.toString() + "\" }";
587 * Builds JSON object with status of error and message containing stack
588 * trace for the specified throwable.
591 * Throwable with stack trace to use as message
596 * { "status" : "error", "message": "some-big-stacktrace" }
599 private String buildJsonResponse(Throwable t) {
600 StringWriter sw = new StringWriter();
601 PrintWriter pw = new PrintWriter(sw);
602 t.printStackTrace(pw);
603 return buildJsonResponse(false, sw.toString());
607 public String getUserId(HttpServletRequest request) throws PortalAPIException {
608 return portalRestApiServiceImpl.getUserId(request);
611 public static IPortalRestAPIService getPortalRestApiServiceImpl() {
612 return portalRestApiServiceImpl;
615 public static void setPortalRestApiServiceImpl(IPortalRestAPIService portalRestApiServiceImpl) {
616 PortalRestAPIProxy.portalRestApiServiceImpl = portalRestApiServiceImpl;