2012-10-08 56 views
15

Me pregunto cómo filtrar el acceso de los usuarios a mi aplicación web mediante su IP usando Spring Security. ¿Debo extender AbstractAuthenticationProcessingFilter o algo así y anular sus métodos a mi manera? En caso afirmativo, ¿podría dar un ejemplo de tal ampliación y ejemplo de descripción de filtro en web.xml? Gracias de antemano.Filtro IP usando Spring Security

P.S. En mi aplicación también tengo soporte de Spring Security (usando el predeterminado org.springframework.web.filter.DelegatingFilterProxy), pero quiero que verifique no solo las credenciales del usuario, sino también su IP.

+0

posible duplicado de http://stackoverflow.com/questions/10147161/authenticating-by-ip-address-in-spring- Gracias por su respuesta, 3-1-smartest-way-to-do-that – Anshu

Respuesta

13

Una forma de hacerlo es utilizar el Web Security Expressions de Spring Security. Por ejemplo:

<http use-expressions="true"> 
    <intercept-url pattern="/admin*" 
     access="hasRole('admin') and hasIpAddress('192.168.1.0/24')"/> 
    ... 
</http> 
+0

Funcionó muy bien. Solo asegúrate de que tienes use-expressions = "true" ya que es necesario que las expresiones de seguridad web funcionen. Aunque la solución tiene eso, no dice explícitamente que sea necesario (lo que me habría ayudado;) – Andre

+2

No es una solución que funcionaría bien en escenarios del mundo real, sin embargo, dado que está codificada en un XML archivo y requiere un reinicio del servidor de la aplicación. – Aquarelle

7

Marque esta aplicación AuthenticationProvider personalizado para la autenticación mediante la dirección 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's 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's 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)); 
    } 

} 

seguridad-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> 

El enfoque se toma de pregunta existente Authenticating By IP Address In Spring 3.1: Smartest Way To Do That?, esto podría ayudar a empezar.

+0

Parece que se ajusta a mi solicitud, pero decidí simplemente usar expresiones de seguridad web debido a su simplicidad. –

0

La respuesta de Anshu es una buena idea de autenticar a un usuario por ip, pero puede no funcionar con la autenticación de cas. Tengo otra resolución, usar un filtro es más adecuado para esta situación.

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; 
    } 
} 

Puede agregar este filtro antes cas como esto:

http.addFilterBefore(ipAuthenticationFilter(), CasAuthenticationFilter.class) 
Cuestiones relacionadas