IpAddressAuthProvider.java
package org.flasby.security;
import java.util.Optional;
import javax.transaction.Transactional;
import org.flasby.entity.BannedIp;
import org.flasby.entity.repository.BannedIpRepository;
import org.flasby.security.servlet.ServletAuthenticationDetails;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.DisabledException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;
import lombok.extern.log4j.Log4j2;
@Log4j2
// @Configuration
@Component
public class IpAddressAuthProvider implements AuthenticationProvider {
/**
* annoyingly, the Spring Auth Manager keeps iterating through its list of
* Auth Providers if one throws an exception unless it's a subclass of
* AccountStatusException. This is really quite crap, it's enough to be returned
* a null Authentication object to try the next provider.
*/
public static class BannedIpAddressException extends DisabledException {
private static final long serialVersionUID = 1L;
BannedIpAddressException(String msg) {
super(msg);
}
}
private final BannedIpRepository bannedIpRepository;
public IpAddressAuthProvider(@Autowired BannedIpRepository bannedIpRepository) {
this.bannedIpRepository = bannedIpRepository;
log.info("Instantiating IpAddressAuthProvider");
}
@Override
public boolean supports(Class<?> authentication) {
boolean retval = UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication) ;
System.err.println("= = = ==> "+authentication+" - is it supported here? "+retval);
return retval;
}
/**
* Invokes the IP Block checks
*/
@Override
@Transactional(dontRollbackOn = AuthenticationException.class)
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
System.err.println("= = = ==> "+authentication.getClass().getName());
System.err.println("= = = ==> "+authentication.getDetails());
if ( authentication.getDetails() instanceof ServletAuthenticationDetails ) {
ServletAuthenticationDetails token = (ServletAuthenticationDetails)authentication.getDetails();
String ipAddress = token.getRemoteAddress();
if ( ipAddress != null ) {
Optional<BannedIp> banned = bannedIpRepository.findById(ipAddress);
banned.ifPresentOrElse(
(x) -> {
if ( x.getFailedCount() > 5 ) throw new BannedIpAddressException("IP Address "+x.getIp()+" is still banned after at least "+x.getFailedCount()+" attempts");
},
() -> {
System.out.println("IP "+ipAddress+" not found in the BannedIp table");
}
);
} else {
log.warn("Can't check if the remote client is banned as we don't know their IP address");
}
} else {
log.error("Unhandled authentication type of "+authentication.getDetails().getClass()+" should be reject this login attempt?" );
}
return null; // Accept this IP Address as not banned and move on to the next Auth check
}
}