CLOUDSTACK-7941: CloudStack should log IP address of actual client even if a ReverseProxy is there
(cherry picked from commit f0a4a639de231929bd63f673c4d6adc6bfb5ca80) Signed-off-by: Rohit Yadav <[email protected]> Project: http://git-wip-us.apache.org/repos/asf/cloudstack/repo Commit: http://git-wip-us.apache.org/repos/asf/cloudstack/commit/6715c6cc Tree: http://git-wip-us.apache.org/repos/asf/cloudstack/tree/6715c6cc Diff: http://git-wip-us.apache.org/repos/asf/cloudstack/diff/6715c6cc Branch: refs/heads/4.5 Commit: 6715c6ccfa68b53a3891f49ec98b568511c9cfb9 Parents: dca38d3 Author: Saksham Srivastava <[email protected]> Authored: Mon Nov 17 16:28:49 2014 +0530 Committer: Rohit Yadav <[email protected]> Committed: Tue Jan 20 11:32:09 2015 +0530 ---------------------------------------------------------------------- server/src/com/cloud/api/ApiServlet.java | 94 +++++++++++++++++++++------ 1 file changed, 73 insertions(+), 21 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/cloudstack/blob/6715c6cc/server/src/com/cloud/api/ApiServlet.java ---------------------------------------------------------------------- diff --git a/server/src/com/cloud/api/ApiServlet.java b/server/src/com/cloud/api/ApiServlet.java index c7d0609..3d2e843 100644 --- a/server/src/com/cloud/api/ApiServlet.java +++ b/server/src/com/cloud/api/ApiServlet.java @@ -16,35 +16,38 @@ // under the License. package com.cloud.api; -import org.apache.cloudstack.api.auth.APIAuthenticationManager; -import org.apache.cloudstack.api.auth.APIAuthenticationType; -import org.apache.cloudstack.api.auth.APIAuthenticator; -import com.cloud.user.Account; -import com.cloud.user.AccountService; -import com.cloud.user.User; -import com.cloud.utils.HttpUtils; -import com.cloud.utils.StringUtils; -import com.cloud.utils.db.EntityManager; +import java.io.UnsupportedEncodingException; +import java.net.URLDecoder; +import java.util.HashMap; +import java.util.Map; + +import javax.inject.Inject; +import javax.servlet.ServletConfig; +import javax.servlet.ServletException; +import javax.servlet.http.HttpServlet; +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; +import javax.servlet.http.HttpSession; + import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.ApiServerService; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.auth.APIAuthenticationManager; +import org.apache.cloudstack.api.auth.APIAuthenticationType; +import org.apache.cloudstack.api.auth.APIAuthenticator; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.managed.context.ManagedContext; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; import org.springframework.web.context.support.SpringBeanAutowiringSupport; -import javax.inject.Inject; -import javax.servlet.ServletConfig; -import javax.servlet.ServletException; -import javax.servlet.http.HttpServlet; -import javax.servlet.http.HttpServletRequest; -import javax.servlet.http.HttpServletResponse; -import javax.servlet.http.HttpSession; -import java.io.UnsupportedEncodingException; -import java.net.URLDecoder; -import java.util.HashMap; -import java.util.Map; +import com.cloud.user.Account; +import com.cloud.user.AccountService; +import com.cloud.user.User; +import com.cloud.utils.HttpUtils; +import com.cloud.utils.StringUtils; +import com.cloud.utils.db.EntityManager; +import com.cloud.utils.net.NetUtils; @Component("apiServlet") @SuppressWarnings("serial") @@ -120,7 +123,7 @@ public class ApiServlet extends HttpServlet { } void processRequestInContext(final HttpServletRequest req, final HttpServletResponse resp) { - final String remoteAddress = req.getRemoteAddr(); + final String remoteAddress = getClientAddress(req); final StringBuilder auditTrailSb = new StringBuilder(128); auditTrailSb.append(" ").append(remoteAddress); auditTrailSb.append(" -- ").append(req.getMethod()).append(' '); @@ -304,4 +307,53 @@ public class ApiServlet extends HttpServlet { CallContext.unregister(); } } + + //This method will try to get login IP of user even if servlet is behind reverseProxy or loadBalancer + private String getClientAddress(HttpServletRequest request) { + String ip = null; + ip = request.getHeader("X-Forwarded-For"); + ip = getCorrectIPAddress(ip); + if (ip != null) { + return ip; + } + + ip = request.getHeader("HTTP_CLIENT_IP"); + ip = getCorrectIPAddress(ip); + if (ip != null) { + return ip; + } + + ip = request.getHeader("HTTP_X_FORWARDED_FOR"); + ip = getCorrectIPAddress(ip); + if (ip != null) { + return ip; + } + + ip = request.getHeader("Remote_Addr"); + ip = getCorrectIPAddress(ip); + if (ip != null) { + return ip; + } + + ip = request.getRemoteAddr(); + return ip; + } + + private String getCorrectIPAddress(String ip) { + if(ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) { + return null; + } + if(NetUtils.isValidIp(ip)) { + return ip; + } + //it could be possible to have multiple IPs in HTTP header, this happens if there are multiple proxy in between + //the client and the servlet, so parse the client IP + String[] ips = ip.split(","); + for(String i : ips) { + if(NetUtils.isValidIp(i.trim())) { + return i.trim(); + } + } + return null; + } }
