ApiServlet extends HttpServlet { void processRequestInContext(final HttpServletRequest req, final HttpServletResponse resp) { final String remoteAddress = getClientAddress(req); final StringBuilder auditTrailSb = new StringBuilder(128); auditTrailSb.append(" ").append(remoteAddress); auditTrailSb.append(" -- ").append(req.getMethod()).append(' '); String responseType = HttpUtils.RESPONSE_TYPE_XML; final Map<String, Object[]> params = new HashMap<String, Object[]>(); params.putAll(req.getParameterMap()); utf8Fixup(req, params); String reqStr = ""; String cleanQueryString = StringUtils.cleanString(req.getQueryString()); if (s_logger.isDebugEnabled()) { reqStr = auditTrailSb.toString() + " " + cleanQueryString; s_logger.debug("===START=== " + reqStr); } try { if (HttpUtils.RESPONSE_TYPE_JSON.equalsIgnoreCase(responseType)) { resp.setContentType(ApiServer.getJSONContentType()); } else if (HttpUtils.RESPONSE_TYPE_XML.equalsIgnoreCase(responseType)){ resp.setContentType(HttpUtils.XML_CONTENT_TYPE); } HttpSession session = req.getSession(false); final Object[] responseTypeParam = params.get(ApiConstants.RESPONSE); if (responseTypeParam != null) { responseType = (String)responseTypeParam[0]; } final Object[] commandObj = params.get(ApiConstants.COMMAND); if (commandObj != null) { final String command = (String) commandObj[0]; APIAuthenticator apiAuthenticator = _authManager.getAPIAuthenticator(command); if (apiAuthenticator != null) { auditTrailSb.append("command="); auditTrailSb.append(command); int httpResponseCode = HttpServletResponse.SC_OK; String responseString = null; if (apiAuthenticator.getAPIType() == APIAuthenticationType.LOGIN_API) { if (session != null) { try { session.invalidate(); } catch (final IllegalStateException ise) { } } session = req.getSession(true); if (ApiServer.isSecureSessionCookieEnabled()) { resp.setHeader("SET-COOKIE", String.format("JSESSIONID=%s;Secure;HttpOnly;Path=/client", session.getId())); if (s_logger.isDebugEnabled()) { if (s_logger.isDebugEnabled()) { s_logger.debug("Session cookie is marked secure!"); } } } } try { responseString = apiAuthenticator.authenticate(command, params, session, InetAddress.getByName(remoteAddress), responseType, auditTrailSb, req, resp); if (session != null && session.getAttribute(ApiConstants.SESSIONKEY) != null) { resp.addHeader("SET-COOKIE", String.format("%s=%s;HttpOnly", ApiConstants.SESSIONKEY, session.getAttribute(ApiConstants.SESSIONKEY))); } } catch (ServerApiException e) { httpResponseCode = e.getErrorCode().getHttpCode(); responseString = e.getMessage(); s_logger.debug("Authentication failure: " + e.getMessage()); } if (apiAuthenticator.getAPIType() == APIAuthenticationType.LOGOUT_API) { if (session != null) { final Long userId = (Long) session.getAttribute("userid"); final Account account = (Account) session.getAttribute("accountobj"); Long accountId = null; if (account != null) { accountId = account.getId(); } auditTrailSb.insert(0, "(userId=" + userId + " accountId=" + accountId + " sessionId=" + session.getId() + ")"); if (userId != null) { _apiServer.logoutUser(userId); } try { session.invalidate(); } catch (final IllegalStateException ignored) { } } Cookie sessionKeyCookie = new Cookie(ApiConstants.SESSIONKEY, ""); sessionKeyCookie.setMaxAge(0); resp.addCookie(sessionKeyCookie); } HttpUtils.writeHttpResponse(resp, responseString, httpResponseCode, responseType, ApiServer.getJSONContentType()); return; } } auditTrailSb.append(cleanQueryString); final boolean isNew = ((session == null) ? true : session.isNew()); Long userId = null; if (!isNew) { userId = (Long)session.getAttribute("userid"); final String account = (String) session.getAttribute("account"); final Object accountObj = session.getAttribute("accountobj"); if (!HttpUtils.validateSessionKey(session, params, req.getCookies(), ApiConstants.SESSIONKEY)) { try { session.invalidate(); } catch (final IllegalStateException ise) { } auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials"); final String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType); HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, ApiServer.getJSONContentType()); return; } if ((userId != null) && (account != null) && (accountObj != null) && _apiServer.verifyUser(userId)) { final String[] command = (String[])params.get(ApiConstants.COMMAND); if (command == null) { s_logger.info("missing command, ignoring request..."); auditTrailSb.append(" " + HttpServletResponse.SC_BAD_REQUEST + " " + "no command specified"); final String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_BAD_REQUEST, "no command specified", params, responseType); HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_BAD_REQUEST, responseType, ApiServer.getJSONContentType()); return; } final User user = _entityMgr.findById(User.class, userId); CallContext.register(user, (Account)accountObj); } else { try { session.invalidate(); } catch (final IllegalStateException ise) { } auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials"); final String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType); HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, ApiServer.getJSONContentType()); return; } } else { CallContext.register(_accountMgr.getSystemUser(), _accountMgr.getSystemAccount()); } if (_apiServer.verifyRequest(params, userId)) { auditTrailSb.insert(0, "(userId=" + CallContext.current().getCallingUserId() + " accountId=" + CallContext.current().getCallingAccount().getId() + " sessionId=" + (session != null ? session.getId() : null) + ")"); params.put("httpmethod", new String[] {req.getMethod()}); final String response = _apiServer.handleRequest(params, responseType, auditTrailSb); HttpUtils.writeHttpResponse(resp, response != null ? response : "", HttpServletResponse.SC_OK, responseType, ApiServer.getJSONContentType()); } else { if (session != null) { try { session.invalidate(); } catch (final IllegalStateException ise) { } } auditTrailSb.append(" " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials and/or request signature"); final String serializedResponse = _apiServer.getSerializedApiError(HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials and/or request signature", params, responseType); HttpUtils.writeHttpResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType, ApiServer.getJSONContentType()); } } catch (final ServerApiException se) { final String serializedResponseText = _apiServer.getSerializedApiError(se, params, responseType); resp.setHeader("X-Description", se.getDescription()); HttpUtils.writeHttpResponse(resp, serializedResponseText, se.getErrorCode().getHttpCode(), responseType, ApiServer.getJSONContentType()); auditTrailSb.append(" " + se.getErrorCode() + " " + se.getDescription()); } catch (final Exception ex) { s_logger.error("unknown exception writing api response", ex); auditTrailSb.append(" unknown exception writing api response"); } finally { s_accessLogger.info(auditTrailSb.toString()); if (s_logger.isDebugEnabled()) { s_logger.debug("===END=== " + reqStr); } CallContext.unregister(); } } ApiServlet(); @Override void init(final ServletConfig config); static final Logger s_logger; }
@SuppressWarnings("unchecked") @Test public void processRequestInContextUnauthorizedGET() { Mockito.when(request.getMethod()).thenReturn("GET"); Mockito.when( apiServer.verifyRequest(Mockito.anyMap(), Mockito.anyLong())) .thenReturn(false); servlet.processRequestInContext(request, response); Mockito.verify(response).setStatus(HttpServletResponse.SC_UNAUTHORIZED); Mockito.verify(apiServer, Mockito.never()).handleRequest( Mockito.anyMap(), Mockito.anyString(), Mockito.any(StringBuilder.class)); }
@SuppressWarnings("unchecked") @Test public void processRequestInContextAuthorizedGet() { Mockito.when(request.getMethod()).thenReturn("GET"); Mockito.when( apiServer.verifyRequest(Mockito.anyMap(), Mockito.anyLong())) .thenReturn(true); servlet.processRequestInContext(request, response); Mockito.verify(response).setStatus(HttpServletResponse.SC_OK); Mockito.verify(apiServer, Mockito.times(1)).handleRequest( Mockito.anyMap(), Mockito.anyString(), Mockito.any(StringBuilder.class)); }
@SuppressWarnings("unchecked") @Test public void processRequestInContextLogout() throws UnknownHostException { Mockito.when(request.getMethod()).thenReturn("GET"); Mockito.when(request.getSession(Mockito.anyBoolean())).thenReturn( session); Mockito.when(session.getAttribute("userid")).thenReturn(1l); Mockito.when(session.getAttribute("accountobj")).thenReturn(account); HashMap<String, String[]> params = new HashMap<String, String[]>(); params.put(ApiConstants.COMMAND, new String[] { "logout" }); Mockito.when(request.getParameterMap()).thenReturn(params); Mockito.when(authenticator.getAPIType()).thenReturn(APIAuthenticationType.LOGOUT_API); servlet.processRequestInContext(request, response); Mockito.verify(authManager).getAPIAuthenticator("logout"); Mockito.verify(authenticator).authenticate(Mockito.anyString(), Mockito.anyMap(), Mockito.isA(HttpSession.class), Mockito.eq(InetAddress.getByName("127.0.0.1")), Mockito.anyString(), Mockito.isA(StringBuilder.class), Mockito.isA(HttpServletRequest.class), Mockito.isA(HttpServletResponse.class)); Mockito.verify(session).invalidate(); }
@SuppressWarnings("unchecked") @Test public void processRequestInContextLogin() throws UnknownHostException { Mockito.when(request.getMethod()).thenReturn("GET"); Mockito.when(request.getSession(Mockito.anyBoolean())).thenReturn( session); HashMap<String, String[]> params = new HashMap<String, String[]>(); params.put(ApiConstants.COMMAND, new String[] { "login" }); params.put(ApiConstants.USERNAME, new String[] { "TEST" }); params.put(ApiConstants.PASSWORD, new String[] { "TEST-PWD" }); params.put(ApiConstants.DOMAIN_ID, new String[] { "42" }); params.put(ApiConstants.DOMAIN, new String[] { "TEST-DOMAIN" }); Mockito.when(request.getParameterMap()).thenReturn(params); servlet.processRequestInContext(request, response); Mockito.verify(authManager).getAPIAuthenticator("login"); Mockito.verify(authenticator).authenticate(Mockito.anyString(), Mockito.anyMap(), Mockito.isA(HttpSession.class), Mockito.eq(InetAddress.getByName("127.0.0.1")), Mockito.anyString(), Mockito.isA(StringBuilder.class), Mockito.isA(HttpServletRequest.class), Mockito.isA(HttpServletResponse.class)); }