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)