2 * ============LICENSE_START==========================================
4 * ===================================================================
5 * Copyright © 2017 AT&T Intellectual Property. All rights reserved.
6 * ===================================================================
8 * Unless otherwise specified, all software contained herein is licensed
9 * under the Apache License, Version 2.0 (the “License”);
10 * you may not use this software except in compliance with the License.
11 * You may obtain a copy of the License at
13 * http://www.apache.org/licenses/LICENSE-2.0
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.
21 * Unless otherwise specified, all documentation contained herein is licensed
22 * under the Creative Commons License, Attribution 4.0 Intl. (the “License”);
23 * you may not use this documentation except in compliance with the License.
24 * You may obtain a copy of the License at
26 * https://creativecommons.org/licenses/by/4.0/
28 * Unless required by applicable law or agreed to in writing, documentation
29 * distributed under the License is distributed on an "AS IS" BASIS,
30 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
31 * See the License for the specific language governing permissions and
32 * limitations under the License.
34 * ============LICENSE_END============================================
36 * ECOMP is a trademark and service mark of AT&T Intellectual Property.
38 package org.onap.portalsdk.core.onboarding.crossapi;
40 import java.io.BufferedReader;
41 import java.io.IOException;
42 import java.io.InputStream;
43 import java.io.InputStreamReader;
44 import java.io.PrintWriter;
45 import java.io.StringWriter;
46 import java.util.List;
49 import javax.servlet.ServletException;
50 import javax.servlet.annotation.WebServlet;
51 import javax.servlet.http.HttpServlet;
52 import javax.servlet.http.HttpServletRequest;
53 import javax.servlet.http.HttpServletResponse;
55 import org.apache.commons.logging.Log;
56 import org.apache.commons.logging.LogFactory;
57 import org.onap.portalsdk.core.onboarding.exception.PortalAPIException;
58 import org.onap.portalsdk.core.onboarding.listener.PortalTimeoutHandler;
59 import org.onap.portalsdk.core.onboarding.rest.RestWebServiceClient;
60 import org.onap.portalsdk.core.onboarding.util.PortalApiConstants;
61 import org.onap.portalsdk.core.onboarding.util.PortalApiProperties;
62 import org.onap.portalsdk.core.restful.domain.EcompRole;
63 import org.onap.portalsdk.core.restful.domain.EcompUser;
65 import com.fasterxml.jackson.core.JsonProcessingException;
66 import com.fasterxml.jackson.core.type.TypeReference;
67 import com.fasterxml.jackson.databind.DeserializationFeature;
68 import com.fasterxml.jackson.databind.ObjectMapper;
71 * This servlet performs the functions described below. It listens on a path
72 * like "/api" (see {@link PortalApiConstants#API_PREFIX}). The servlet checks
73 * for authorized access and rejects unauthorized requests.
75 * <LI>Proxies user (i.e., browser) requests for web analytics. The GET method
76 * fetches javascript from the Portal and returns it. The POST method forwards
77 * data sent by the browser on to Portal. These requests are checked for a valid
78 * User UID in a header; these requests do NOT use the application
79 * username-password header.</LI>
80 * <LI>Responds to ECOMP Portal API requests to query and update user, role and
81 * user-role information. The servlet proxies all requests on to a local Java
82 * class that implements {@link IPortalRestAPIService}. These requests must have
83 * the application username-password header.</LI>
85 * This servlet will not start if the required portal.properties file is not
86 * found on the classpath.
89 @WebServlet(urlPatterns = { PortalApiConstants.API_PREFIX + "/*" })
90 public class PortalRestAPIProxy extends HttpServlet implements IPortalRestAPIService {
91 private static final long serialVersionUID = 1L;
93 private static final String contentTypeAppJson = "application/json";
95 private final Log logger = LogFactory.getLog(getClass());
98 * Mapper for JSON to object etc.
100 private final ObjectMapper mapper = new ObjectMapper();
103 * Client-supplied class that implements our interface.
105 private static IPortalRestAPIService portalRestApiServiceImpl;
107 public PortalRestAPIProxy() {
108 // Ensure that any additional fields sent by the Portal
109 // will be ignored when creating objects.
110 mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
114 public void init() throws ServletException {
115 String className = PortalApiProperties.getProperty(PortalApiConstants.PORTAL_API_IMPL_CLASS);
116 if (className == null)
117 throw new ServletException(
118 "init: Failed to find class name property " + PortalApiConstants.PORTAL_API_IMPL_CLASS);
120 logger.debug("init: creating instance of class " + className);
121 Class<?> implClass = Class.forName(className);
122 portalRestApiServiceImpl = (IPortalRestAPIService) (implClass.getConstructor().newInstance());
123 } catch (Exception ex) {
124 throw new ServletException("init: Failed to find or instantiate class " + className, ex);
129 protected void doPost(HttpServletRequest request, HttpServletResponse response)
130 throws IOException, ServletException {
131 if (portalRestApiServiceImpl == null) {
132 // Should never happen due to checks in init()
133 logger.error("doPost: no service class instance");
134 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
135 response.getWriter().write(buildJsonResponse(false, "Misconfigured - no instance of service class"));
138 String requestUri = request.getRequestURI();
139 String responseJson = "";
140 String storeAnalyticsContextPath = "/storeAnalytics";
141 if (requestUri.endsWith(PortalApiConstants.API_PREFIX + storeAnalyticsContextPath)) {
144 userId = getUserId(request);
145 } catch (PortalAPIException e) {
146 logger.error("Issue with invoking getUserId implemenation !!! ", e);
147 throw new ServletException(e);
149 if (userId == null || userId.length() == 0) {
150 logger.debug("doPost: userId is null or empty");
151 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
152 responseJson = buildJsonResponse(false, "Not authorized for " + storeAnalyticsContextPath);
154 // User ID obtained from request
156 String credential = PortalApiProperties.getProperty(PortalApiConstants.UEB_APP_KEY);
157 // for now lets also pass uebkey as user name and password
158 String requestBody = readRequestBody(request);
159 @SuppressWarnings("unchecked")
160 Map<String, String> bodyMap = mapper.readValue(requestBody, Map.class);
162 bodyMap.put("userid", userId);
163 requestBody = mapper.writeValueAsString(bodyMap);
164 responseJson = RestWebServiceClient.getInstance().postPortalContent(storeAnalyticsContextPath,
165 userId, credential, null, credential, credential, "application/json", requestBody, true);
166 if (logger.isDebugEnabled())
167 logger.debug("doPost: postPortalContent returns " + responseJson);
168 response.setStatus(HttpServletResponse.SC_OK);
169 } catch (Exception ex) {
170 logger.error("doPost: " + storeAnalyticsContextPath + " caught exception", ex);
171 responseJson = buildJsonResponse(ex);
172 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
175 writeAndFlush(response, contentTypeAppJson, responseJson);
179 boolean secure = false;
181 secure = isAppAuthenticated(request);
182 } catch (PortalAPIException ex) {
183 logger.error("doPost: isAppAuthenticated threw exception", ex);
184 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
185 response.getWriter().write(buildJsonResponse(false, "Failed to authenticate request"));
189 if (logger.isDebugEnabled())
190 logger.debug("doPost: isAppAuthenticated answered false");
191 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
192 writeAndFlush(response, contentTypeAppJson, buildJsonResponse(false, "Not authorized"));
197 String requestBody = readRequestBody(request);
198 if (logger.isDebugEnabled())
199 logger.debug("doPost: URI = " + requestUri + ", payload = " + requestBody);
204 * 1. /user <-- save user
206 * 2. /user/{loginId} <-- edit user
208 * 3. /user/{loginId}/roles <-- save roles for user
211 // On success return the empty string.
213 if (requestUri.endsWith("/updateSessionTimeOuts")) {
214 if (updateSessionTimeOuts(requestBody)) {
215 if (logger.isDebugEnabled())
216 logger.debug("doPost: updated session timeouts");
217 response.setStatus(HttpServletResponse.SC_OK);
219 String msg = "Failed to update session time outs";
220 logger.error("doPost: " + msg);
221 responseJson = buildJsonResponse(false, msg);
222 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
224 } else if (requestUri.endsWith("/timeoutSession")) {
225 String portalJSessionId = request.getParameter("portalJSessionId");
226 if (portalJSessionId == null) {
227 portalJSessionId = "";
229 if (timeoutSession(portalJSessionId)) {
230 if (logger.isDebugEnabled())
231 logger.debug("doPost: timed out session");
232 response.setStatus(HttpServletResponse.SC_OK);
234 String msg = "Failed to timeout session";
235 logger.error("doPost: " + msg);
236 responseJson = buildJsonResponse(false, msg);
237 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
240 // Example: /user <-- create user
241 if (requestUri.endsWith(PortalApiConstants.API_PREFIX + "/user")) {
243 EcompUser user = mapper.readValue(requestBody, EcompUser.class);
245 if (logger.isDebugEnabled())
246 logger.debug("doPost: pushUser: success");
247 responseJson = buildJsonResponse(true, null);
248 response.setStatus(HttpServletResponse.SC_OK);
249 } catch (Exception ex) {
250 responseJson = buildJsonResponse(ex);
251 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
252 logger.error("doPost: pushUser: caught exception", ex);
255 // Example: /user/fi241c <-- edit user fi241c
256 if (requestUri.contains(PortalApiConstants.API_PREFIX + "/user/") && !(requestUri.endsWith("/roles"))) {
257 String loginId = requestUri.substring(requestUri.lastIndexOf('/') + 1);
259 EcompUser user = mapper.readValue(requestBody, EcompUser.class);
260 editUser(loginId, user);
261 if (logger.isDebugEnabled())
262 logger.debug("doPost: editUser: success");
263 responseJson = buildJsonResponse(true, null);
264 response.setStatus(HttpServletResponse.SC_OK);
265 } catch (Exception ex) {
266 responseJson = buildJsonResponse(ex);
267 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
268 logger.error("doPost: editUser: caught exception", ex);
271 // Example: /user/{loginId}/roles <-- save roles for user
272 if (requestUri.contains(PortalApiConstants.API_PREFIX + "/user/") && requestUri.endsWith("/roles")) {
273 String loginId = requestUri.substring(requestUri.indexOf("/user/") + ("/user").length() + 1,
274 requestUri.lastIndexOf('/'));
276 TypeReference<List<EcompRole>> typeRef = new TypeReference<List<EcompRole>>() {
278 List<EcompRole> roles = mapper.readValue(requestBody, typeRef);
279 pushUserRole(loginId, roles);
280 if (logger.isDebugEnabled())
281 logger.debug("doPost: pushUserRole: success");
282 responseJson = buildJsonResponse(true, null);
283 response.setStatus(HttpServletResponse.SC_OK);
284 } catch (Exception ex) {
285 responseJson = buildJsonResponse(ex);
286 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
287 logger.error("doPost: pushUserRole: caught exception", ex);
290 String msg = "doPost: no match for request " + requestUri;
292 responseJson = buildJsonResponse(false, msg);
293 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
295 } catch (Exception ex) {
296 logger.error("doPost: Failed to process request " + requestUri, ex);
297 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
298 responseJson = buildJsonResponse(ex);
301 writeAndFlush(response, contentTypeAppJson, responseJson);
306 protected void doGet(HttpServletRequest request, HttpServletResponse response)
307 throws IOException, ServletException {
309 if (portalRestApiServiceImpl == null) {
310 // Should never happen due to checks in init()
311 logger.error("doGet: no service class instance");
312 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
313 writeAndFlush(response, contentTypeAppJson,
314 buildJsonResponse(false, "Misconfigured - no instance of service class"));
318 String requestUri = request.getRequestURI();
319 String responseString = "";
320 String contentType = contentTypeAppJson;
322 String webAnalyticsContextPath = "/analytics";
323 if (requestUri.endsWith(PortalApiConstants.API_PREFIX + webAnalyticsContextPath)) {
326 userId = getUserId(request);
327 } catch (PortalAPIException e) {
328 logger.error("Issue with invoking getUserId implemenation !!! ", e);
329 throw new ServletException(e);
331 if (userId == null || userId.length() == 0) {
332 logger.debug("doGet: userId is null or empty");
333 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
334 responseString = buildJsonResponse(false, "Not authorized for " + webAnalyticsContextPath);
336 // User ID obtained from request
338 String credential = PortalApiProperties.getProperty(PortalApiConstants.UEB_APP_KEY);
339 // for now lets also pass uebkey as user name and password
340 contentType = "text/javascript";
342 responseString = RestWebServiceClient.getInstance().getPortalContent(webAnalyticsContextPath,
343 userId, credential, null, credential, credential, true);
344 if (logger.isDebugEnabled())
345 logger.debug("doGet: " + webAnalyticsContextPath + ": " + responseString);
346 response.setStatus(HttpServletResponse.SC_OK);
347 } catch (Exception ex) {
348 responseString = buildJsonResponse(ex);
349 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
350 logger.error("doGet: " + webAnalyticsContextPath + " caught exception", ex);
353 writeAndFlush(response, contentType, responseString);
357 boolean secure = false;
359 secure = isAppAuthenticated(request);
360 } catch (PortalAPIException ex) {
361 logger.error("doGet: isAppAuthenticated threw exception", ex);
362 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
363 writeAndFlush(response, contentTypeAppJson, buildJsonResponse(false, "Failed to authenticate request"));
368 if (logger.isDebugEnabled())
369 logger.debug("doGet: isAppAuthenticated answered false");
370 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
371 writeAndFlush(response, contentTypeAppJson, buildJsonResponse(false, "Not authorized"));
375 String responseJson = null;
377 // Ignore any request body in a GET.
378 // String requestBody = readRequestBody(request);
379 if (logger.isDebugEnabled())
380 logger.debug("doGet: URI = " + requestUri);
383 * 1. /roles <-- get roles
385 * 2. /user/{loginId} <-- get user
387 * 3. /users <-- get all users
389 * 4. /user/{loginId}/roles <-- get roles for user
392 if (requestUri.endsWith("/sessionTimeOuts")) {
393 responseJson = getSessionTimeOuts();
394 if (responseJson != null && responseJson.length() > 0) {
395 if (logger.isDebugEnabled())
396 logger.debug("doGet: got session timeouts");
397 response.setStatus(HttpServletResponse.SC_OK);
399 String msg = "Failed to get session time outs";
400 logger.error("doGet: " + msg);
401 responseJson = buildJsonResponse(false, msg);
402 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
405 // Example: /users <-- get all users
406 if (requestUri.endsWith(PortalApiConstants.API_PREFIX + "/users")) {
408 List<EcompUser> users = getUsers();
409 responseJson = mapper.writeValueAsString(users);
410 if (logger.isDebugEnabled())
411 logger.debug("doGet: getUsers: " + responseJson);
412 } catch (Exception ex) {
413 responseJson = buildJsonResponse(ex);
414 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
415 logger.error("doGet: getUsers: caught exception", ex);
418 // Example: /roles <-- get all roles
420 if (requestUri.endsWith(PortalApiConstants.API_PREFIX + "/roles")) {
422 List<EcompRole> roles = getAvailableRoles(getUserId(request));
423 responseJson = mapper.writeValueAsString(roles);
424 if (logger.isDebugEnabled())
425 logger.debug("doGet: getAvailableRoles: " + responseJson);
426 } catch (Exception ex) {
427 responseJson = buildJsonResponse(ex);
428 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
429 logger.error("doGet: getAvailableRoles: caught exception", ex);
432 // Example: /user/fi241c <-- get user fi241c
433 if (requestUri.contains(PortalApiConstants.API_PREFIX + "/user/") && !requestUri.endsWith("/roles")) {
434 String loginId = requestUri.substring(requestUri.lastIndexOf('/') + 1);
436 EcompUser user = getUser(loginId);
437 responseJson = mapper.writeValueAsString(user);
438 if (logger.isDebugEnabled())
439 logger.debug("doGet: getUser: " + responseJson);
440 } catch (Exception ex) {
441 responseJson = buildJsonResponse(ex);
442 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
443 logger.error("doGet: getUser: caught exception", ex);
446 // Example: /user/fi241c/roles <-- get roles for user fi241c
447 else if (requestUri.contains(PortalApiConstants.API_PREFIX + "/user/") && requestUri.endsWith("/roles")) {
448 String loginId = requestUri.substring(requestUri.indexOf("/user/") + ("/user").length() + 1,
449 requestUri.lastIndexOf('/'));
451 List<EcompRole> roles = getUserRoles(loginId);
452 responseJson = mapper.writeValueAsString(roles);
453 if (logger.isDebugEnabled())
454 logger.debug("doGet: getUserRoles: " + responseJson);
455 } catch (Exception ex) {
456 responseJson = buildJsonResponse(ex);
457 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
458 logger.error("doGet: getUserRoles: caught exception", ex);
461 logger.warn("doGet: no match found for request");
462 responseJson = buildJsonResponse(false, "No match for request");
463 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
465 } catch (Exception ex) {
466 logger.error("doGet: Failed to process request", ex);
467 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
468 responseJson = buildJsonResponse(ex);
470 writeAndFlush(response, contentTypeAppJson, responseJson);
473 public String getSessionTimeOuts() {
474 return PortalTimeoutHandler.gatherSessionExtensions();
477 public boolean timeoutSession(String portalJSessionId) {
478 return PortalTimeoutHandler.invalidateSession(portalJSessionId);
481 public boolean updateSessionTimeOuts(String sessionMap) {
482 return PortalTimeoutHandler.updateSessionExtensions(sessionMap);
486 public void pushUser(EcompUser user) throws PortalAPIException {
487 portalRestApiServiceImpl.pushUser(user);
491 public void editUser(String loginId, EcompUser user) throws PortalAPIException {
492 portalRestApiServiceImpl.editUser(loginId, user);
496 public EcompUser getUser(String loginId) throws PortalAPIException {
497 return portalRestApiServiceImpl.getUser(loginId);
501 public List<EcompUser> getUsers() throws PortalAPIException {
502 return portalRestApiServiceImpl.getUsers();
506 public List<EcompRole> getAvailableRoles(String requestedLoginId) throws PortalAPIException {
507 return portalRestApiServiceImpl.getAvailableRoles(requestedLoginId);
511 public void pushUserRole(String loginId, List<EcompRole> roles) throws PortalAPIException {
512 portalRestApiServiceImpl.pushUserRole(loginId, roles);
516 public List<EcompRole> getUserRoles(String loginId) throws PortalAPIException {
517 return portalRestApiServiceImpl.getUserRoles(loginId);
521 public boolean isAppAuthenticated(HttpServletRequest request) throws PortalAPIException {
522 return portalRestApiServiceImpl.isAppAuthenticated(request);
526 * Sets the content type and writes the response.
530 * @param responseBody
531 * @throws IOException
533 private void writeAndFlush(HttpServletResponse response, String contentType, String responseBody)
535 response.setContentType(contentType);
536 PrintWriter out = response.getWriter();
537 out.print(responseBody);
542 * Reads the request body and closes the input stream.
545 * @return String read from the request, the empty string if nothing is read.
546 * @throws IOException
548 private static String readRequestBody(HttpServletRequest request) throws IOException {
551 StringBuilder stringBuilder = new StringBuilder();
552 BufferedReader bufferedReader = null;
554 InputStream inputStream = request.getInputStream();
555 if (inputStream != null) {
556 bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
557 char[] charBuffer = new char[1024];
559 while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
560 stringBuilder.append(charBuffer, 0, bytesRead);
563 stringBuilder.append("");
566 if (bufferedReader != null) {
568 bufferedReader.close();
569 } catch (IOException ex) {
574 body = stringBuilder.toString();
579 * Builds JSON object with status + message response body.
582 * True to indicate success, false to signal failure.
584 * Message to include in the response object; ignored if null.
588 * { "status" : "ok" (or "error"), "message": "some explanation" }
591 private String buildJsonResponse(boolean success, String msg) {
592 PortalAPIResponse response = new PortalAPIResponse(success, msg);
595 json = mapper.writeValueAsString(response);
596 } catch (JsonProcessingException ex) {
597 // Truly should never, ever happen
598 json = "{ \"status\": \"error\",\"message\":\"" + ex.toString() + "\" }";
604 * Builds JSON object with status of error and message containing stack trace
605 * for the specified throwable.
608 * Throwable with stack trace to use as message
613 * { "status" : "error", "message": "some-big-stacktrace" }
616 private String buildJsonResponse(Throwable t) {
617 StringWriter sw = new StringWriter();
618 PrintWriter pw = new PrintWriter(sw);
619 t.printStackTrace(pw);
620 return buildJsonResponse(false, sw.toString());
624 public String getUserId(HttpServletRequest request) throws PortalAPIException {
625 return portalRestApiServiceImpl.getUserId(request);
628 public static IPortalRestAPIService getPortalRestApiServiceImpl() {
629 return portalRestApiServiceImpl;
632 public static void setPortalRestApiServiceImpl(IPortalRestAPIService portalRestApiServiceImpl) {
633 PortalRestAPIProxy.portalRestApiServiceImpl = portalRestApiServiceImpl;