How to find user IPs in Spring Security?

I need to find those users who are logged into our application.
We are using Spring Security, and there should be a way to find out the IP addresses of users.

I think this data is stored in their sessions. In Spring Security, current sessions are stored in SessionRegistry . From this class, I can have a list of authenticated users and some session information. (Using getAllPrincipals , getAllSessions and getSessionInformation )

The question is, how can I access the IP addresses of current users? Think, we should provide the service only to a known region.
SessionInformation does not help much, since it does not contain much information.

+6
source share
3 answers

I think validation will be achieved using hasIpAddress http expression

See section 15.2 Web Security Expressions

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

If you need more flexibility, you can implement your own IP address verification service based on IpAddressMatcher:

 <bean id="ipCheckService" class="my.IpCheckService"> </bean> <security:http auto-config="false" access-denied-page="/accessDenied.jsp" use-expressions="true"> <security:intercept-url pattern="/login.jsp" access="@ipCheckService.isValid(request)" /> 

bean implementation:

 public class IpCheckService { public boolean isValid(HttpServletRequest request) { //This service is a bean so you can inject other dependencies, //for example load the white list of IPs from the database IpAddressMatcher matcher = new IpAddressMatcher("192.168.1.0/24"); try { return matcher.matches(request); } catch (UnsupportedOperationException e) { return false; } } } 

update : you can try to get the current IP address of the user as follows:

  public static String getRequestRemoteAddr(){ HttpServletRequest request = ((ServletRequestAttributes)RequestContextHolder.currentRequestAttributes()) .getRequest(); return request.getRemoteAddr(); } 

update Information about the connection between IP addresses and sessions can only be collected from different sources (for example, listening to AuthenticationSuccessEvent and SessionDestroyedEvent events, implementing a filter, or using an AOP interceptor). Spring Security does not store this information because it is useless, because the IP address has some significance only when the server processes ServletRequest .

The IP address can change (the user can use a proxy server), so we can only check various types of events, for example, log in with some credentials, access the service from another IP address or do some suspicious actions.

+14
source

You can use HttpServletRequest to get the IP address of the user. (SpringSecurity developers do the same in their hasIpAddress (...) statement, which is placed in the WebSecurityExpressionRoot class).

For example, you can get HttpServletRequest in two ways:

1) Using RequestContextHolder:

 HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder .getRequestAttributes()).getRequest(); 

2) Using auto-negotiation:

 @Autowired private HttpServletRequest request; 

I took it from here .

Then, using the HttpServletRequest, you can get the IP address this way:

 String address = request.getRemoteAddr(); 

And here is how addresses are compared in spring security:

 /** * Takes a specific IP address or a range using the IP/Netmask (eg 192.168.1.0/24 or 202.24.0.0/14). * * @param ipAddress the address or range of addresses from which the request must come. * @return true if the IP address of the current request is in the required range. */ public boolean hasIpAddress(String ipAddress) { return (new IpAddressMatcher(ipAddress).matches(request)); } 

And class IpAddressMatcher:

 public final class IpAddressMatcher implements RequestMatcher { private final int nMaskBits; private final InetAddress requiredAddress; /** * Takes a specific IP address or a range specified using the * IP/Netmask (eg 192.168.1.0/24 or 202.24.0.0/14). * * @param ipAddress the address or range of addresses from which the request must come. */ public IpAddressMatcher(String ipAddress) { if (ipAddress.indexOf('/') > 0) { String[] addressAndMask = StringUtils.split(ipAddress, "/"); ipAddress = addressAndMask[0]; nMaskBits = Integer.parseInt(addressAndMask[1]); } else { nMaskBits = -1; } requiredAddress = parseAddress(ipAddress); } public boolean matches(HttpServletRequest request) { return matches(request.getRemoteAddr()); } public boolean matches(String address) { InetAddress remoteAddress = parseAddress(address); if (!requiredAddress.getClass().equals(remoteAddress.getClass())) { return false; } if (nMaskBits < 0) { return remoteAddress.equals(requiredAddress); } byte[] remAddr = remoteAddress.getAddress(); byte[] reqAddr = requiredAddress.getAddress(); int oddBits = nMaskBits % 8; int nMaskBytes = nMaskBits/8 + (oddBits == 0 ? 0 : 1); byte[] mask = new byte[nMaskBytes]; Arrays.fill(mask, 0, oddBits == 0 ? mask.length : mask.length - 1, (byte)0xFF); if (oddBits != 0) { int finalByte = (1 << oddBits) - 1; finalByte <<= 8-oddBits; mask[mask.length - 1] = (byte) finalByte; } // System.out.println("Mask is " + new sun.misc.HexDumpEncoder().encode(mask)); for (int i=0; i < mask.length; i++) { if ((remAddr[i] & mask[i]) != (reqAddr[i] & mask[i])) { return false; } } return true; } private InetAddress parseAddress(String address) { try { return InetAddress.getByName(address); } catch (UnknownHostException e) { throw new IllegalArgumentException("Failed to parse address" + address, e); } } } 

EDIT:

According to related questions here and here, you can add a custom IP address to the session using a custom filter. And then get this information from the session associated with the user, where necessary. For example, you can put IP user information as follows:

 public class MonitoringFilter extends GenericFilterBean{ @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { HttpServletRequest httpRequest = (HttpServletRequest) request; String userIp = httpRequest.getRemoteAddr(); httpRequest.getSession().setAttribute("userIp", userIp); // Add other attributes to session if necessary } 
+3
source

You can get the IP address from the WebAuthenticationDetails object, which can be obtained from Authentication .

 Object details = SecurityContextHolder.getContext().getAuthentication().getDetails(); if (details instanceof WebAuthenticationDetails) ipAddress = ((WebAuthenticationDetails) details).getRemoteAddress(); 
+1
source

Source: https://habr.com/ru/post/922663/


All Articles