package de.is24.infrastructure.gridfs.http.utils; import de.is24.infrastructure.gridfs.http.security.AuthenticationDetails; import org.bouncycastle.util.IPAddress; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.security.authentication.AuthenticationDetailsSource; import org.springframework.stereotype.Component; import javax.servlet.http.HttpServletRequest; import java.net.Inet4Address; import java.net.Inet6Address; import java.net.UnknownHostException; import java.util.Set; import static org.apache.commons.lang.StringUtils.isNotBlank; import static org.springframework.util.StringUtils.commaDelimitedListToSet; import static org.springframework.util.StringUtils.trimAllWhitespace; @Component public class HostnameResolver implements AuthenticationDetailsSource<HttpServletRequest, AuthenticationDetails> { private static final Logger LOGGER = LoggerFactory.getLogger(HostnameResolver.class); protected static final String X_FORWARDED_FOR = "X-Forwarded-For"; public static final String ADDRESS_SEPERATOR = ","; private final Set<String> loadBalancerIPs; @Autowired public HostnameResolver(@Value("${loadbalancer.ips:}") String loadBalancerIPs) { LOGGER.info("Initializing HostnameResolver with loadbalancer IPs {}", loadBalancerIPs); this.loadBalancerIPs = commaDelimitedListToSet(trimAllWhitespace(loadBalancerIPs)); } public HostName remoteHost(HttpServletRequest request) { if (loadBalancerIPs.contains(request.getRemoteAddr()) && isNotBlank(request.getHeader(X_FORWARDED_FOR))) { String[] ips = trimAllWhitespace(request.getHeader(X_FORWARDED_FOR)).split(ADDRESS_SEPERATOR); for (int i = ips.length - 1; i >= 0; i--) { String ip = ips[i]; if (i == 0 || !loadBalancerIPs.contains(ip)) { LOGGER.debug("Request comes from known proxy or load balancer: {}", ip); return hostname(ip); } } LOGGER.debug("Multi proxy request comes from known proxy, but X-Forwarded-For header contains unknown second proxy: {}", request.getHeader(X_FORWARDED_FOR)); } return hostname(request.getRemoteHost()); } private HostName hostname(String hostnameOrIP) { String result = hostnameOrIP; try { if (IPAddress.isValidIPv4(hostnameOrIP)) { result = Inet4Address.getByName(hostnameOrIP).getHostName(); } else if (IPAddress.isValidIPv6(hostnameOrIP)) { result = Inet6Address.getByName(hostnameOrIP).getHostName(); } } catch (UnknownHostException e) { LOGGER.info("could not resolve hostname for {}", hostnameOrIP); } LOGGER.debug("resolved hostname for {} is {}", hostnameOrIP, result); return new HostName(result); } @Override public AuthenticationDetails buildDetails(HttpServletRequest request) { return new AuthenticationDetails(remoteHost(request)); } }