IP-фильтр с помощью Spring Безопасность
Мне интересно, как фильтровать доступ пользователей к моему веб-приложению по их IP-адресу с помощью Spring Security.
Должен ли я расширять AbstractAuthenticationProcessingFilter
или что-то в этом роде и переопределять его методы по-своему?
Если да, не могли бы вы привести пример такого расширения и пример описания фильтра в web.xml
?
Спасибо заранее.
P.S. В моем приложении у меня также есть Spring Поддержка безопасности (с использованием по умолчанию org.springframework.web.filter.DelegatingFilterProxy
), но я хочу, чтобы он проверял не только учетные данные пользователя, но и их IP.
Ответы
Ответ 1
Один из способов сделать это - использовать Spring Безопасность Выражения безопасности Web. Например:
<http use-expressions="true">
<intercept-url pattern="/admin*"
access="hasRole('admin') and hasIpAddress('192.168.1.0/24')"/>
...
</http>
Ответ 2
Проверьте эту пользовательскую реализацию AuthenticationProvider для аутентификации по IP-адресу
// Authentication Provider To Authenticate By IP Address With Allowed IPs
// Stored in a db table
package acme.com.controller.security;
//import acme.com.controller.security.CustomUserInfoHolder;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.authentication.WebAuthenticationDetails;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.authority.mapping.GrantedAuthoritiesMapper;
import org.springframework.security.core.authority.mapping.NullAuthoritiesMapper;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.userdetails.UserDetails;
import org.apache.log4j.Logger;
public class CustomIPAddressAuthenticationProvider implements AuthenticationProvider
{
private static final Logger logger = Logger.getLogger(CustomIPAddressAuthenticationProvider.class);
private GrantedAuthoritiesMapper authoritiesMapper = new NullAuthoritiesMapper();
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
WebAuthenticationDetails wad = null;
String userIPAddress = null;
boolean isAuthenticatedByIP = false;
// Get the IP address of the user tyring to use the site
wad = (WebAuthenticationDetails) authentication.getDetails();
userIPAddress = wad.getRemoteAddress();
logger.debug("userIPAddress == " + userIPAddress);
// Compare the user IP Address with the IP address in the database
// stored in the USERS_AUTHENTICATED_BY_IP table & joined to the
// USERS tabe to make sure the IP Address has a current user
//isAuthenticatedByIP = someDataObject.hasIPAddress(userIPAddress);
isAuthenticatedByIP = true;
// Authenticated, the user IP address matches one in the database
if (isAuthenticatedByIP)
{
logger.debug("isAuthenticatedByIP is true, IP Addresses match");
UserDetails user = null;
UsernamePasswordAuthenticationToken result = null;
result = new UsernamePasswordAuthenticationToken("John Principal",
"PlaceholderPWE");
result.setDetails(authentication.getDetails());
return result;
}
// Authentication didn't happen, return null to signal that the
// AuthenticationManager should move on to the next Authentication provider
return null;
}
@Override
public boolean supports(Class<? extends Object> authentication)
{
// copied it from AbstractUserDetailsAuthenticationProvider
return(UsernamePasswordAuthenticationToken.class.isAssignableFrom(authentication));
}
}
безопасности web.xml
<s:http pattern="/login*" security="none"/>
<s:http pattern="/search*" security="none"/>
<s:http pattern="/css/**" security="none"/>
<s:http pattern="/js/**" security="none"/>
<s:http pattern="/images/**" security="none"/>
<s:http auto-config="true" use-expressions="true">
<s:intercept-url pattern="/**" access="isAuthenticated()" />
<s:form-login login-page="/login"
authentication-failure-url="/loginfailed" />
<s:logout logout-success-url="/logout" />
</s:http>
<s:ldap-server url = "ldap://ldap-itc.smen.acme.com:636/o=acme.com"/>
<bean id="customIPAddressAuthenticationProvider" class="com.acme.controller.security.CustomIPAddressAuthenticationProvider" />
<s:authentication-manager>
<!-- Proposed: Custom Authentication Provider: Try To Authenticate BY IP Address First, IF NOT, Authenticate WiTh THE LDAP Authentication Provider -->
<s:authentication-provider ref="customIPAddressAuthenticationProvider" />
<s:ldap-authentication-provider user-dn-pattern="uid={0},ou=People"/>
</s:authentication-manager>
</beans>
Подход берется из существующего вопроса Аутентификация по IP-адресу В Spring 3.1: самый умный способ сделать это? это может помочь начать.
Ответ 3
Ответ Anshu - это хорошая идея аутентификации пользователя по ip, но он может не работать с аутентификацией cas. У меня есть другое разрешение, использование фильтра больше подходит для этой ситуации.
public class IPAuthenticationFilter extends AbstractAuthenticationProcessingFilter {
private AuthenticationUserDetailsService<CasAssertionAuthenticationToken> authenticationUserDetailsService;
private static Set<String> ipWhitelist;
@Autowired
private AppProperty appProperty;
@PostConstruct
public void init() {
ipWhitelist = new HashSet<>(Arrays.asList(appProperty.getIpWhitelist()));
setAuthenticationSuccessHandler(new AuthenticationSuccessHandler() {
@Override
public void onAuthenticationSuccess(
HttpServletRequest httpServletRequest,
HttpServletResponse httpServletResponse,
Authentication authentication) throws IOException, ServletException {
// do nothing
}
});
}
public IPAuthenticationFilter() {
super("/");
}
public Authentication attemptAuthentication(HttpServletRequest request, HttpServletResponse response)
throws AuthenticationException, IOException {
String userName = request.getHeader(appProperty.getHeaderCurUser());
Assertion assertion = new AssertionImpl(userName);
CasAssertionAuthenticationToken token = new CasAssertionAuthenticationToken(assertion, "");
UserDetails userDetails = authenticationUserDetailsService.loadUserDetails(token);
CasAuthenticationToken result = new CasAuthenticationToken(
"an-id-for-ip-auth",
userDetails,
request.getRemoteAddr(),
userDetails.getAuthorities(),
userDetails,
assertion
);
return result;
}
protected boolean requiresAuthentication(HttpServletRequest request, HttpServletResponse response) {
String userName = request.getHeader(appProperty.getHeaderCurUser());
return ipWhitelist.contains(request.getRemoteAddr()) && !StringUtils.isEmpty(userName);
}
protected void successfulAuthentication(
HttpServletRequest request,
HttpServletResponse response,
FilterChain chain,
Authentication authResult) throws IOException, ServletException {
super.successfulAuthentication(request, response, chain, authResult);
chain.doFilter(request, response);
}
public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> getAuthenticationUserDetailsService() {
return authenticationUserDetailsService;
}
public void setAuthenticationUserDetailsService(
AuthenticationUserDetailsService<CasAssertionAuthenticationToken> authenticationUserDetailsService) {
this.authenticationUserDetailsService = authenticationUserDetailsService;
}
}
Вы можете добавить этот фильтр перед тем как это:
http.addFilterBefore(ipAuthenticationFilter(), CasAuthenticationFilter.class)