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 {
92 private static final long serialVersionUID = 1L;
94 private static final String APPLICATION_JSON = "application/json";
96 private static final Log logger = LogFactory.getLog(PortalRestAPIProxy.class);
99 * Mapper for JSON to object etc.
101 private final ObjectMapper mapper = new ObjectMapper();
104 * Client-supplied class that implements our interface.
106 private static IPortalRestAPIService portalRestApiServiceImpl;
107 private static final String isAccessCentralized = PortalApiProperties
108 .getProperty(PortalApiConstants.ROLE_ACCESS_CENTRALIZED);
109 private static final String errorMessage = "Access Management is not allowed for Centralized applications." ;
110 private static final String isCentralized = "remote";
113 public PortalRestAPIProxy() {
114 // Ensure that any additional fields sent by the Portal
115 // will be ignored when creating objects.
116 mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
120 public void init() throws ServletException {
121 String className = PortalApiProperties.getProperty(PortalApiConstants.PORTAL_API_IMPL_CLASS);
122 if (className == null)
123 throw new ServletException(
124 "init: Failed to find class name property " + PortalApiConstants.PORTAL_API_IMPL_CLASS);
126 logger.debug("init: creating instance of class " + className);
127 Class<?> implClass = Class.forName(className);
128 portalRestApiServiceImpl = (IPortalRestAPIService) (implClass.getConstructor().newInstance());
129 } catch (Exception ex) {
130 throw new ServletException("init: Failed to find or instantiate class " + className, ex);
135 protected void doPost(HttpServletRequest request, HttpServletResponse response)
136 throws IOException, ServletException {
137 if (portalRestApiServiceImpl == null) {
138 // Should never happen due to checks in init()
139 logger.error("doPost: no service class instance");
140 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
141 response.getWriter().write(buildJsonResponse(false, "Misconfigured - no instance of service class"));
144 String requestUri = request.getRequestURI();
145 String responseJson = "";
146 String storeAnalyticsContextPath = "/storeAnalytics";
147 if (requestUri.endsWith(PortalApiConstants.API_PREFIX + storeAnalyticsContextPath)) {
150 userId = getUserId(request);
151 } catch (PortalAPIException e) {
152 logger.error("Issue with invoking getUserId implemenation !!! ", e);
153 throw new ServletException(e);
155 if (userId == null || userId.length() == 0) {
156 logger.debug("doPost: userId is null or empty");
157 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
158 responseJson = buildJsonResponse(false, "Not authorized for " + storeAnalyticsContextPath);
160 // User ID obtained from request
162 String credential = PortalApiProperties.getProperty(PortalApiConstants.UEB_APP_KEY);
163 // for now lets also pass uebkey as user name and password
164 String requestBody = readRequestBody(request);
165 @SuppressWarnings("unchecked")
166 Map<String, String> bodyMap = mapper.readValue(requestBody, Map.class);
168 bodyMap.put("userid", userId);
169 requestBody = mapper.writeValueAsString(bodyMap);
170 responseJson = RestWebServiceClient.getInstance().postPortalContent(storeAnalyticsContextPath,
171 userId, credential, null, credential, credential, "application/json", requestBody, true);
172 logger.debug("doPost: postPortalContent returns " + responseJson);
173 response.setStatus(HttpServletResponse.SC_OK);
174 } catch (Exception ex) {
175 logger.error("doPost: " + storeAnalyticsContextPath + " caught exception", ex);
176 responseJson = buildJsonResponse(ex);
177 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
180 writeAndFlush(response, APPLICATION_JSON, responseJson);
184 boolean secure = false;
186 secure = isAppAuthenticated(request);
187 } catch (PortalAPIException ex) {
188 logger.error("doPost: isAppAuthenticated threw exception", ex);
189 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
190 response.getWriter().write(buildJsonResponse(false, "Failed to authenticate request"));
194 logger.debug("doPost: isAppAuthenticated answered false");
195 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
196 writeAndFlush(response, APPLICATION_JSON, buildJsonResponse(false, "Not authorized"));
201 String requestBody = readRequestBody(request);
202 if (logger.isDebugEnabled())
203 logger.debug("doPost: URI = " + requestUri + ", payload = " + requestBody);
208 * 1. /user <-- save user
210 * 2. /user/{loginId} <-- edit user
212 * 3. /user/{loginId}/roles <-- save roles for user
215 // On success return the empty string.
217 if (requestUri.endsWith("/updateSessionTimeOuts")) {
218 if (updateSessionTimeOuts(requestBody)) {
219 logger.debug("doPost: updated session timeouts");
220 response.setStatus(HttpServletResponse.SC_OK);
222 String msg = "Failed to update session time outs";
223 logger.error("doPost: " + msg);
224 responseJson = buildJsonResponse(false, msg);
225 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
227 } else if (requestUri.endsWith("/timeoutSession")) {
228 String portalJSessionId = request.getParameter("portalJSessionId");
229 if (portalJSessionId == null) {
230 portalJSessionId = "";
232 if (timeoutSession(portalJSessionId)) {
233 logger.debug("doPost: timed out session");
234 response.setStatus(HttpServletResponse.SC_OK);
236 String msg = "Failed to timeout session";
237 logger.error("doPost: " + msg);
238 responseJson = buildJsonResponse(false, msg);
239 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
242 // Example: /user <-- create user
243 if (requestUri.endsWith(PortalApiConstants.API_PREFIX + "/user")) {
245 if (isCentralized.equals(isAccessCentralized)) {
246 responseJson = buildJsonResponse(true, errorMessage);
247 response.setStatus(HttpServletResponse.SC_OK);
249 EcompUser user = mapper.readValue(requestBody, EcompUser.class);
251 if (logger.isDebugEnabled())
252 logger.debug("doPost: pushUser: success");
253 responseJson = buildJsonResponse(true, null);
254 response.setStatus(HttpServletResponse.SC_OK);
256 } catch (Exception ex) {
257 responseJson = buildJsonResponse(ex);
258 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
259 logger.error("doPost: pushUser: caught exception", ex);
262 // Example: /user/abc <-- edit user abc
263 if (requestUri.contains(PortalApiConstants.API_PREFIX + "/user/") && !(requestUri.endsWith("/roles"))) {
264 String loginId = requestUri.substring(requestUri.lastIndexOf('/') + 1);
266 if (isCentralized.equals(isAccessCentralized)) {
267 responseJson = buildJsonResponse(true, errorMessage);
268 response.setStatus(HttpServletResponse.SC_OK);
270 EcompUser user = mapper.readValue(requestBody, EcompUser.class);
271 editUser(loginId, user);
272 if (logger.isDebugEnabled())
273 logger.debug("doPost: editUser: success");
274 responseJson = buildJsonResponse(true, null);
275 response.setStatus(HttpServletResponse.SC_OK);
277 } catch (Exception ex) {
278 responseJson = buildJsonResponse(ex);
279 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
280 logger.error("doPost: editUser: caught exception", ex);
283 // Example: /user/{loginId}/roles <-- save roles for user
284 if (requestUri.contains(PortalApiConstants.API_PREFIX + "/user/") && requestUri.endsWith("/roles")) {
285 String loginId = requestUri.substring(requestUri.indexOf("/user/") + ("/user").length() + 1,
286 requestUri.lastIndexOf('/'));
288 if (isCentralized.equals(isAccessCentralized)) {
289 responseJson = buildJsonResponse(true, errorMessage);
290 response.setStatus(HttpServletResponse.SC_OK);
292 TypeReference<List<EcompRole>> typeRef = new TypeReference<List<EcompRole>>() {
294 List<EcompRole> roles = mapper.readValue(requestBody, typeRef);
295 pushUserRole(loginId, roles);
296 if (logger.isDebugEnabled())
297 logger.debug("doPost: pushUserRole: success");
298 responseJson = buildJsonResponse(true, null);
299 response.setStatus(HttpServletResponse.SC_OK);
301 } catch (Exception ex) {
302 responseJson = buildJsonResponse(ex);
303 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
304 logger.error("doPost: pushUserRole: caught exception", ex);
307 String msg = "doPost: no match for request " + requestUri;
309 responseJson = buildJsonResponse(false, msg);
310 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
312 } catch (Exception ex) {
313 logger.error("doPost: Failed to process request " + requestUri, ex);
314 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
315 responseJson = buildJsonResponse(ex);
318 writeAndFlush(response, APPLICATION_JSON, responseJson);
323 protected void doGet(HttpServletRequest request, HttpServletResponse response)
324 throws IOException, ServletException {
326 if (portalRestApiServiceImpl == null) {
327 // Should never happen due to checks in init()
328 logger.error("doGet: no service class instance");
329 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
330 writeAndFlush(response, APPLICATION_JSON,
331 buildJsonResponse(false, "Misconfigured - no instance of service class"));
335 String requestUri = request.getRequestURI();
336 String contentType = APPLICATION_JSON;
337 String webAnalyticsContextPath = "/analytics";
338 if (requestUri.endsWith(PortalApiConstants.API_PREFIX + webAnalyticsContextPath)) {
339 String responseString;
342 userId = getUserId(request);
343 } catch (PortalAPIException e) {
344 logger.error("Issue with invoking getUserId implemenation !!! ", e);
345 throw new ServletException(e);
347 if (userId == null || userId.length() == 0) {
348 logger.debug("doGet: userId is null or empty");
349 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
350 responseString = buildJsonResponse(false, "Not authorized for " + webAnalyticsContextPath);
352 // User ID obtained from request
354 String credential = PortalApiProperties.getProperty(PortalApiConstants.UEB_APP_KEY);
355 // for now lets also pass uebkey as user name and password
356 contentType = "text/javascript";
358 responseString = RestWebServiceClient.getInstance().getPortalContent(webAnalyticsContextPath,
359 userId, credential, null, credential, credential, true);
360 if (logger.isDebugEnabled())
361 logger.debug("doGet: " + webAnalyticsContextPath + ": " + responseString);
362 response.setStatus(HttpServletResponse.SC_OK);
363 } catch (Exception ex) {
364 responseString = buildJsonResponse(ex);
365 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
366 logger.error("doGet: " + webAnalyticsContextPath + " caught exception", ex);
369 writeAndFlush(response, contentType, responseString);
373 boolean secure = false;
375 secure = isAppAuthenticated(request);
376 } catch (PortalAPIException ex) {
377 logger.error("doGet: isAppAuthenticated threw exception", ex);
378 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
379 writeAndFlush(response, APPLICATION_JSON, buildJsonResponse(false, "Failed to authenticate request"));
384 if (logger.isDebugEnabled())
385 logger.debug("doGet: isAppAuthenticated answered false");
386 response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
387 writeAndFlush(response, APPLICATION_JSON, buildJsonResponse(false, "Not authorized"));
391 String responseJson = null;
393 // Ignore any request body in a GET.
394 logger.debug("doGet: URI = " + requestUri);
397 * 1. /roles <-- get roles
399 * 2. /user/{loginId} <-- get user
401 * 3. /users <-- get all users
403 * 4. /user/{loginId}/roles <-- get roles for user
406 if (requestUri.endsWith("/sessionTimeOuts")) {
408 responseJson = getSessionTimeOuts();
409 logger.debug("doGet: got session timeouts");
410 response.setStatus(HttpServletResponse.SC_OK);
411 } catch(Exception ex) {
412 String msg = "Failed to get session time outs";
413 logger.error("doGet: " + msg);
414 responseJson = buildJsonResponse(false, msg);
415 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
418 // Example: /users <-- get all users
419 if (requestUri.endsWith(PortalApiConstants.API_PREFIX + "/users")) {
421 List<EcompUser> users = getUsers();
422 responseJson = mapper.writeValueAsString(users);
423 if (logger.isDebugEnabled())
424 logger.debug("doGet: getUsers: " + responseJson);
425 } catch (Exception ex) {
426 responseJson = buildShortJsonResponse(ex);
427 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
428 logger.error("doGet: getUsers: caught exception", ex);
431 // Example: /roles <-- get all roles
433 if (requestUri.endsWith(PortalApiConstants.API_PREFIX + "/roles")) {
435 List<EcompRole> roles = getAvailableRoles(getUserId(request));
436 responseJson = mapper.writeValueAsString(roles);
437 if (logger.isDebugEnabled())
438 logger.debug("doGet: getAvailableRoles: " + responseJson);
439 } catch (Exception ex) {
440 responseJson = buildJsonResponse(ex);
441 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
442 logger.error("doGet: getAvailableRoles: caught exception", ex);
445 // Example: /user/abc <-- get user abc
446 if (requestUri.contains(PortalApiConstants.API_PREFIX + "/user/") && !requestUri.endsWith("/roles")) {
447 String loginId = requestUri.substring(requestUri.lastIndexOf('/') + 1);
449 EcompUser user = getUser(loginId);
450 responseJson = mapper.writeValueAsString(user);
451 if (logger.isDebugEnabled())
452 logger.debug("doGet: getUser: " + responseJson);
453 } catch (Exception ex) {
454 responseJson = buildJsonResponse(ex);
455 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
456 logger.error("doGet: getUser: caught exception", ex);
459 // Example: /user/abc/roles <-- get roles for user abc
460 else if (requestUri.contains(PortalApiConstants.API_PREFIX + "/user/") && requestUri.endsWith("/roles")) {
461 String loginId = requestUri.substring(requestUri.indexOf("/user/") + ("/user").length() + 1,
462 requestUri.lastIndexOf('/'));
464 List<EcompRole> roles = getUserRoles(loginId);
465 responseJson = mapper.writeValueAsString(roles);
466 if (logger.isDebugEnabled())
467 logger.debug("doGet: getUserRoles: " + responseJson);
468 } catch (Exception ex) {
469 responseJson = buildJsonResponse(ex);
470 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
471 logger.error("doGet: getUserRoles: caught exception", ex);
474 logger.warn("doGet: no match found for request");
475 responseJson = buildJsonResponse(false, "No match for request");
476 response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
478 } catch (Exception ex) {
479 logger.error("doGet: Failed to process request", ex);
480 response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
481 responseJson = buildJsonResponse(ex);
483 writeAndFlush(response, APPLICATION_JSON, responseJson);
486 public String getSessionTimeOuts() {
487 return PortalTimeoutHandler.gatherSessionExtensions();
490 public boolean timeoutSession(String portalJSessionId) {
491 return PortalTimeoutHandler.invalidateSession(portalJSessionId);
494 public boolean updateSessionTimeOuts(String sessionMap) {
495 return PortalTimeoutHandler.updateSessionExtensions(sessionMap);
499 public void pushUser(EcompUser user) throws PortalAPIException {
500 portalRestApiServiceImpl.pushUser(user);
504 public void editUser(String loginId, EcompUser user) throws PortalAPIException {
505 portalRestApiServiceImpl.editUser(loginId, user);
509 public EcompUser getUser(String loginId) throws PortalAPIException {
510 return portalRestApiServiceImpl.getUser(loginId);
514 public List<EcompUser> getUsers() throws PortalAPIException {
515 return portalRestApiServiceImpl.getUsers();
519 public List<EcompRole> getAvailableRoles(String requestedLoginId) throws PortalAPIException {
520 return portalRestApiServiceImpl.getAvailableRoles(requestedLoginId);
524 public void pushUserRole(String loginId, List<EcompRole> roles) throws PortalAPIException {
525 portalRestApiServiceImpl.pushUserRole(loginId, roles);
529 public List<EcompRole> getUserRoles(String loginId) throws PortalAPIException {
530 return portalRestApiServiceImpl.getUserRoles(loginId);
534 public boolean isAppAuthenticated(HttpServletRequest request) throws PortalAPIException {
535 return portalRestApiServiceImpl.isAppAuthenticated(request);
539 * Sets the content type and writes the response.
543 * @param responseBody
544 * @throws IOException
546 private void writeAndFlush(HttpServletResponse response, String contentType, String responseBody)
548 response.setContentType(contentType);
549 PrintWriter out = response.getWriter();
550 out.print(responseBody);
555 * Reads the request body and closes the input stream.
558 * @return String read from the request, the empty string if nothing is read.
559 * @throws IOException
561 private static String readRequestBody(HttpServletRequest request) throws IOException {
564 StringBuilder stringBuilder = new StringBuilder();
565 BufferedReader bufferedReader = null;
567 InputStream inputStream = request.getInputStream();
568 if (inputStream != null) {
569 bufferedReader = new BufferedReader(new InputStreamReader(inputStream));
570 char[] charBuffer = new char[1024];
572 while ((bytesRead = bufferedReader.read(charBuffer)) > 0) {
573 stringBuilder.append(charBuffer, 0, bytesRead);
576 stringBuilder.append("");
579 if (bufferedReader != null) {
581 bufferedReader.close();
582 } catch (IOException ex) {
583 logger.error("readRequestBody", ex);
587 body = stringBuilder.toString();
592 * Builds JSON object with status + message response body.
595 * True to indicate success, false to signal failure.
597 * Message to include in the response object; ignored if null.
601 * { "status" : "ok" (or "error"), "message": "some explanation" }
604 private String buildJsonResponse(boolean success, String msg) {
605 PortalAPIResponse response = new PortalAPIResponse(success, msg);
608 json = mapper.writeValueAsString(response);
609 } catch (JsonProcessingException ex) {
610 // Truly should never, ever happen
611 logger.error("buildJsonResponse", ex);
612 json = "{ \"status\": \"error\",\"message\":\"" + ex.toString() + "\" }";
618 * Builds JSON object with status of error and message containing stack trace
619 * for the specified throwable.
622 * Throwable with stack trace to use as message
627 * { "status" : "error", "message": "some-big-stacktrace" }
630 private String buildJsonResponse(Throwable t) {
631 StringWriter sw = new StringWriter();
632 PrintWriter pw = new PrintWriter(sw);
633 t.printStackTrace(pw);
634 return buildJsonResponse(false, sw.toString());
637 private String buildShortJsonResponse(Throwable t)
639 String errorMessage = t.getMessage();
640 return buildJsonResponse(false, errorMessage);
644 public String getUserId(HttpServletRequest request) throws PortalAPIException {
645 return portalRestApiServiceImpl.getUserId(request);
648 public static IPortalRestAPIService getPortalRestApiServiceImpl() {
649 return portalRestApiServiceImpl;
652 public static void setPortalRestApiServiceImpl(IPortalRestAPIService portalRestApiServiceImpl) {
653 PortalRestAPIProxy.portalRestApiServiceImpl = portalRestApiServiceImpl;