package de.asideas.crowdsource.security;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.AnonymousAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.web.authentication.AnonymousAuthenticationFilter;
import org.springframework.stereotype.Component;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
@Component
public class IPBasedAnonymousAuthenticationFilter extends AnonymousAuthenticationFilter {
private static final Logger LOG = LoggerFactory.getLogger(IPBasedAnonymousAuthenticationFilter.class);
@Value("${de.asideas.crowdsource.trustedips:*}")
private String trustedIps;
public IPBasedAnonymousAuthenticationFilter() {
super("ANONYMOUS");
}
@Override
protected Authentication createAuthentication(HttpServletRequest request) {
final ArrayList<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(new SimpleGrantedAuthority(Roles.ROLE_UNTRUSTED_ANONYMOUS));
if (ipWhiteListed(request.getRemoteAddr()) || forwardedForTrusted(request)) {
authorities.add(new SimpleGrantedAuthority(Roles.ROLE_TRUSTED_ANONYMOUS));
}
return new AnonymousAuthenticationToken("ANONYMOUS", "ANONYMOUS", authorities);
}
private boolean forwardedForTrusted(HttpServletRequest request) {
final String forwardedFor = request.getHeader("X-Forwarded-For");
if (StringUtils.isBlank(forwardedFor)) {
return false;
}
for (String forwardedForEntry : forwardedFor.split(",")) {
if (ipWhiteListed(forwardedForEntry.trim())) {
return true;
}
}
return false;
}
private boolean ipWhiteListed(String ip) {
if ("*".equals(trustedIps)) {
return true;
}
for (String trustedPattern : trustedIps.split(",")) {
if (ipMatches(ip, trustedPattern)) {
return true;
}
}
return false;
}
private boolean ipMatches(String ip, String trustedPattern) {
String[] ipSegments = ip.split("\\.");
String[] trustedSegments = trustedPattern.split("\\.");
if (ipSegments.length != 4 || trustedSegments.length != 4) {
LOG.error("invalid segment length for either ip: {} or trusted pattern: {}", ip, trustedPattern);
return false;
}
return "*".equals(trustedSegments[0]) || ipSegments[0].equals(trustedSegments[0])
&& "*".equals(trustedSegments[1]) || ipSegments[1].equals(trustedSegments[1])
&& "*".equals(trustedSegments[2]) || ipSegments[2].equals(trustedSegments[2])
&& "*".equals(trustedSegments[3]) || ipSegments[3].equals(trustedSegments[3]);
}
}