public String getSerializedApiError( ServerApiException ex, Map<String, Object[]> apiCommandParams, String responseType) { String responseName = null; Class<?> cmdClass = null; String responseText = null; if (ex == null) { // this call should not be invoked with null exception return getSerializedApiError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Some internal error happened", apiCommandParams, responseType); } try { if (ex.getErrorCode() == ApiErrorCode.UNSUPPORTED_ACTION_ERROR || apiCommandParams == null || apiCommandParams.isEmpty()) { responseName = "errorresponse"; } else { Object cmdObj = apiCommandParams.get("command"); // cmd name can be null when "command" parameter is missing in // the request if (cmdObj != null) { String cmdName = ((String[]) cmdObj)[0]; cmdClass = getCmdClass(cmdName); if (cmdClass != null) { responseName = ((BaseCmd) cmdClass.newInstance()).getCommandName(); } else { responseName = "errorresponse"; } } } ExceptionResponse apiResponse = new ExceptionResponse(); apiResponse.setErrorCode(ex.getErrorCode().getHttpCode()); apiResponse.setErrorText(ex.getDescription()); apiResponse.setResponseName(responseName); ArrayList<String> idList = ex.getIdProxyList(); if (idList != null) { for (int i = 0; i < idList.size(); i++) { apiResponse.addProxyObject(idList.get(i)); } } // Also copy over the cserror code and the function/layer in which // it was thrown. apiResponse.setCSErrorCode(ex.getCSErrorCode()); SerializationContext.current().setUuidTranslation(true); responseText = ApiResponseSerializer.toSerializedString(apiResponse, responseType); } catch (Exception e) { s_logger.error("Exception responding to http request", e); } return responseText; }
@SuppressWarnings("unchecked") private void processRequest(HttpServletRequest req, HttpServletResponse resp) { StringBuffer auditTrailSb = new StringBuffer(); auditTrailSb.append(" " + req.getRemoteAddr()); auditTrailSb.append(" -- " + req.getMethod() + " "); // get the response format since we'll need it in a couple of places String responseType = BaseCmd.RESPONSE_TYPE_XML; Map<String, Object[]> params = new HashMap<String, Object[]>(); params.putAll(req.getParameterMap()); // // For HTTP GET requests, it seems that HttpServletRequest.getParameterMap() actually tries // to unwrap URL encoded content from ISO-9959-1. // // After failed in using setCharacterEncoding() to control it, end up with following hacking : // for all GET requests, // we will override it with our-own way of UTF-8 based URL decoding. // utf8Fixup(req, params); try { HttpSession session = req.getSession(false); Object[] responseTypeParam = params.get("response"); if (responseTypeParam != null) { responseType = (String) responseTypeParam[0]; } Object[] commandObj = params.get("command"); if (commandObj != null) { String command = (String) commandObj[0]; if ("logout".equalsIgnoreCase(command)) { // if this is just a logout, invalidate the session and return if (session != null) { Long userId = (Long) session.getAttribute("userid"); 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 (IllegalStateException ise) { } } auditTrailSb.append("command=logout"); auditTrailSb.append(" " + HttpServletResponse.SC_OK); writeResponse( resp, getLogoutSuccessResponse(responseType), HttpServletResponse.SC_OK, responseType); return; } else if ("login".equalsIgnoreCase(command)) { auditTrailSb.append("command=login"); // if this is a login, authenticate the user and return if (session != null) { try { session.invalidate(); } catch (IllegalStateException ise) { } } session = req.getSession(true); String[] username = (String[]) params.get("username"); String[] password = (String[]) params.get("password"); String[] domainIdArr = (String[]) params.get("domainid"); if (domainIdArr == null) { domainIdArr = (String[]) params.get("domainId"); } String[] domainName = (String[]) params.get("domain"); Long domainId = null; if ((domainIdArr != null) && (domainIdArr.length > 0)) { try { domainId = new Long(Long.parseLong(domainIdArr[0])); auditTrailSb.append(" domainid=" + domainId); // building the params for POST call } catch (NumberFormatException e) { s_logger.warn("Invalid domain id entered by user"); auditTrailSb.append( " " + HttpServletResponse.SC_UNAUTHORIZED + " " + "Invalid domain id entered, please enter a valid one"); String serializedResponse = _apiServer.getSerializedApiError( HttpServletResponse.SC_UNAUTHORIZED, "Invalid domain id entered, please enter a valid one", params, responseType, null); writeResponse( resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType); } } String domain = null; if (domainName != null) { domain = domainName[0]; auditTrailSb.append(" domain=" + domain); if (domain != null) { // ensure domain starts with '/' and ends with '/' if (!domain.endsWith("/")) { domain += '/'; } if (!domain.startsWith("/")) { domain = "/" + domain; } } } if (username != null) { String pwd = ((password == null) ? null : password[0]); try { _apiServer.loginUser(session, username[0], pwd, domainId, domain, params); auditTrailSb.insert( 0, "(userId=" + session.getAttribute("userid") + " accountId=" + ((Account) session.getAttribute("accountobj")).getId() + " sessionId=" + session.getId() + ")"); String loginResponse = getLoginSuccessResponse(session, responseType); writeResponse(resp, loginResponse, HttpServletResponse.SC_OK, responseType); return; } catch (CloudAuthenticationException ex) { // TODO: fall through to API key, or just fail here w/ auth error? (HTTP 401) try { session.invalidate(); } catch (IllegalStateException ise) { } auditTrailSb.append( " " + BaseCmd.ACCOUNT_ERROR + " " + ex.getMessage() != null ? ex.getMessage() : "failed to authenticate user, check if username/password are correct"); String serializedResponse = _apiServer.getSerializedApiError( BaseCmd.ACCOUNT_ERROR, ex.getMessage() != null ? ex.getMessage() : "failed to authenticate user, check if username/password are correct", params, responseType, null); writeResponse(resp, serializedResponse, BaseCmd.ACCOUNT_ERROR, responseType); return; } } } } auditTrailSb.append(req.getQueryString()); boolean isNew = ((session == null) ? true : session.isNew()); // Initialize an empty context and we will update it after we have verified the request below, // we no longer rely on web-session here, verifyRequest will populate user/account information // if a API key exists UserContext.registerContext( _accountMgr.getSystemUser().getId(), _accountMgr.getSystemAccount(), null, false); Long userId = null; if (!isNew) { userId = (Long) session.getAttribute("userid"); String account = (String) session.getAttribute("account"); Object accountObj = session.getAttribute("accountobj"); String sessionKey = (String) session.getAttribute("sessionkey"); String[] sessionKeyParam = (String[]) params.get("sessionkey"); if ((sessionKeyParam == null) || (sessionKey == null) || !sessionKey.equals(sessionKeyParam[0])) { try { session.invalidate(); } catch (IllegalStateException ise) { } auditTrailSb.append( " " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials"); String serializedResponse = _apiServer.getSerializedApiError( HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType, null); writeResponse( resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType); return; } // Do a sanity check here to make sure the user hasn't already been deleted if ((userId != null) && (account != null) && (accountObj != null) && _apiServer.verifyUser(userId)) { String[] command = (String[]) params.get("command"); if (command == null) { s_logger.info("missing command, ignoring request..."); auditTrailSb.append( " " + HttpServletResponse.SC_BAD_REQUEST + " " + "no command specified"); String serializedResponse = _apiServer.getSerializedApiError( HttpServletResponse.SC_BAD_REQUEST, "no command specified", params, responseType, null); writeResponse( resp, serializedResponse, HttpServletResponse.SC_BAD_REQUEST, responseType); return; } UserContext.updateContext(userId, (Account) accountObj, session.getId()); } else { // Invalidate the session to ensure we won't allow a request across management server // restarts if the userId // was serialized to the // stored session try { session.invalidate(); } catch (IllegalStateException ise) { } auditTrailSb.append( " " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials"); String serializedResponse = _apiServer.getSerializedApiError( HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials", params, responseType, null); writeResponse( resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType); return; } } if (_apiServer.verifyRequest(params, userId)) { /* * if (accountObj != null) { Account userAccount = (Account)accountObj; if (userAccount.getType() == * Account.ACCOUNT_TYPE_NORMAL) { params.put(BaseCmd.Properties.USER_ID.getName(), new String[] { userId }); * params.put(BaseCmd.Properties.ACCOUNT.getName(), new String[] { account }); * params.put(BaseCmd.Properties.DOMAIN_ID.getName(), new String[] { domainId }); * params.put(BaseCmd.Properties.ACCOUNT_OBJ.getName(), new Object[] { accountObj }); } else { * params.put(BaseCmd.Properties.USER_ID.getName(), new String[] { userId }); * params.put(BaseCmd.Properties.ACCOUNT_OBJ.getName(), new Object[] { accountObj }); } } * * // update user context info here so that we can take information if the request is authenticated // via api * key mechanism updateUserContext(params, session != null ? session.getId() : null); */ auditTrailSb.insert( 0, "(userId=" + UserContext.current().getCallerUserId() + " accountId=" + UserContext.current().getCaller().getId() + " sessionId=" + (session != null ? session.getId() : null) + ")"); try { String response = _apiServer.handleRequest(params, false, responseType, auditTrailSb); writeResponse( resp, response != null ? response : "", HttpServletResponse.SC_OK, responseType); } catch (ServerApiException se) { String serializedResponseText = _apiServer.getSerializedApiError( se.getErrorCode(), se.getDescription(), params, responseType, null); resp.setHeader("X-Description", se.getDescription()); writeResponse(resp, serializedResponseText, se.getErrorCode(), responseType); auditTrailSb.append(" " + se.getErrorCode() + " " + se.getDescription()); } } else { if (session != null) { try { session.invalidate(); } catch (IllegalStateException ise) { } } auditTrailSb.append( " " + HttpServletResponse.SC_UNAUTHORIZED + " " + "unable to verify user credentials and/or request signature"); String serializedResponse = _apiServer.getSerializedApiError( HttpServletResponse.SC_UNAUTHORIZED, "unable to verify user credentials and/or request signature", params, responseType, null); writeResponse(resp, serializedResponse, HttpServletResponse.SC_UNAUTHORIZED, responseType); } } catch (Exception ex) { if (ex instanceof ServerApiException && ((ServerApiException) ex).getErrorCode() == BaseCmd.UNSUPPORTED_ACTION_ERROR) { ServerApiException se = (ServerApiException) ex; String serializedResponseText = _apiServer.getSerializedApiError( se.getErrorCode(), se.getDescription(), params, responseType, null); resp.setHeader("X-Description", se.getDescription()); writeResponse(resp, serializedResponseText, se.getErrorCode(), responseType); auditTrailSb.append(" " + se.getErrorCode() + " " + se.getDescription()); } else { s_logger.error("unknown exception writing api response", ex); auditTrailSb.append(" unknown exception writing api response"); } } finally { s_accessLogger.info(auditTrailSb.toString()); // cleanup user context to prevent from being peeked in other request context UserContext.unregisterContext(); } }
// NOTE: handle() only handles over the wire (OTW) requests from integration.api.port 8096 // If integration api port is not configured, actual OTW requests will be received by ApiServlet @SuppressWarnings({"unchecked", "rawtypes"}) @Override public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException { // Create StringBuffer to log information in access log StringBuffer sb = new StringBuffer(); HttpServerConnection connObj = (HttpServerConnection) context.getAttribute("http.connection"); if (connObj instanceof SocketHttpServerConnection) { InetAddress remoteAddr = ((SocketHttpServerConnection) connObj).getRemoteAddress(); sb.append(remoteAddr.toString() + " -- "); } sb.append(StringUtils.cleanString(request.getRequestLine().toString())); try { List<NameValuePair> paramList = null; try { paramList = URLEncodedUtils.parse(new URI(request.getRequestLine().getUri()), "UTF-8"); } catch (URISyntaxException e) { s_logger.error("Error parsing url request", e); } // Use Multimap as the parameter map should be in the form (name=String, value=String[]) // So parameter values are stored in a list for the same name key // APITODO: Use Guava's (import com.google.common.collect.Multimap;) // (Immutable)Multimap<String, String> paramMultiMap = HashMultimap.create(); // Map<String, Collection<String>> parameterMap = paramMultiMap.asMap(); Map parameterMap = new HashMap<String, String[]>(); String responseType = BaseCmd.RESPONSE_TYPE_XML; for (NameValuePair param : paramList) { if (param.getName().equalsIgnoreCase("response")) { responseType = param.getValue(); continue; } parameterMap.put(param.getName(), new String[] {param.getValue()}); } // Check responseType, if not among valid types, fallback to JSON if (!(responseType.equals(BaseCmd.RESPONSE_TYPE_JSON) || responseType.equals(BaseCmd.RESPONSE_TYPE_XML))) responseType = BaseCmd.RESPONSE_TYPE_XML; try { // always trust commands from API port, user context will always be // UID_SYSTEM/ACCOUNT_ID_SYSTEM UserContext.registerContext(_systemUser.getId(), _systemAccount, null, true); sb.insert( 0, "(userId=" + User.UID_SYSTEM + " accountId=" + Account.ACCOUNT_ID_SYSTEM + " sessionId=" + null + ") "); String responseText = handleRequest(parameterMap, true, responseType, sb); sb.append(" 200 " + ((responseText == null) ? 0 : responseText.length())); writeResponse(response, responseText, HttpStatus.SC_OK, responseType, null); } catch (ServerApiException se) { String responseText = getSerializedApiError(se, parameterMap, responseType); writeResponse( response, responseText, se.getErrorCode().getHttpCode(), responseType, se.getDescription()); sb.append(" " + se.getErrorCode() + " " + se.getDescription()); } catch (RuntimeException e) { // log runtime exception like NullPointerException to help identify the source easier s_logger.error("Unhandled exception, ", e); throw e; } } finally { s_accessLogger.info(sb.toString()); UserContext.unregisterContext(); } }