1. Overview
In this tutorial, we’ll discuss how to whitelist IP ranges in Spring Security.
We’ll take a look at both Java and XML configurations. We’ll also see how to whitelist IP range using a custom AuthenticationProvider.
2. Java Configuration
First, let’s explore the Java configuration.
We can use hasIpAddress() to allow only users with a given IP address to access a specific resource.
Here’s a simple security configuration using hasIpAddress():
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/login").permitAll() .antMatchers("/foos/**").hasIpAddress("11.11.11.11") .anyRequest().authenticated() .and() .formLogin().permitAll() .and() .csrf().disable(); } // ... }
In this configuration, only users with the IP address “11.11.11.11” will be able to access the ”/foos” resource. There’s also no need for users with the whitelisted IP to log in before they access the “/foos/” URL.
If we want users with “11.11.11.11” IP to log in first, we can use the method in an expression of the form:
//... .antMatchers("/foos/**") .access("isAuthenticated() and hasIpAddress('11.11.11.11')") //...
3. XML Configuration
Next, let’s see how to whitelist an IP range using XML configuration:
We’ll use hasIpAddress() here as well:
<security:http> <security:form-login/> <security:intercept-url pattern="/login" access="permitAll()" /> <security:intercept-url pattern="/foos/**" access="hasIpAddress('11.11.11.11')" /> <security:intercept-url pattern="/**" access="isAuthenticated()" /> </security:http> // ...
4. Live Test
Now, here’s a simple live test to make sure everything is working properly.
First, we’ll make sure any user can access the home page after login:
@Test public void givenUser_whenGetHomePage_thenOK() { Response response = RestAssured.given().auth().form("john", "123") .get("http://localhost:8082/"); assertEquals(200, response.getStatusCode()); assertTrue(response.asString().contains("Welcome")); }
Next, we’ll make sure even authenticated users can’t access the “/foos” resource unless their IP is whitelisted:
@Test public void givenUserWithWrongIP_whenGetFooById_thenForbidden() { Response response = RestAssured.given().auth().form("john", "123") .get("http://localhost:8082/foos/1"); assertEquals(403, response.getStatusCode()); assertTrue(response.asString().contains("Forbidden")); }
Note that we aren’t able to access “/foos” resource from localhost “127.0.0.1” as only users with “11.11.11.11” are able to access it.
5. Whitelisting Using a Custom AuthenticationProvider
Finally, we’ll see how to whitelist an IP range by building a custom AuthenticationProvider.
We’ve seen how we can use hasIpAddress() to whitelist an IP range and how to mix it with other expressions. But sometimes, we need more customization.
In the following example, we have multiple IP addresses whitelisted and only users from those IP addresses can log in to our system:
@Component public class CustomIpAuthenticationProvider implements AuthenticationProvider { Set<String> whitelist = new HashSet<String>(); public CustomIpAuthenticationProvider() { whitelist.add("11.11.11.11"); whitelist.add("12.12.12.12"); } @Override public Authentication authenticate(Authentication auth) throws AuthenticationException { WebAuthenticationDetails details = (WebAuthenticationDetails) auth.getDetails(); String userIp = details.getRemoteAddress(); if(! whitelist.contains(userIp)){ throw new BadCredentialsException("Invalid IP Address"); } //... }
Now, we’ll use our CustomIpAuthenticationProvider in our security configuration:
@Configuration @EnableWebSecurity public class SecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private CustomIpAuthenticationProvider authenticationProvider; @Override protected void configure(AuthenticationManagerBuilder auth) throws Exception { auth.authenticationProvider(authenticationProvider); } @Override protected void configure(HttpSecurity http) throws Exception { http.authorizeRequests() .antMatchers("/login").permitAll() .anyRequest().authenticated() .and().formLogin().permitAll() .and().csrf().disable(); } }
Here, we used the WebAuthenticationDetails getRemoteAddress() method to obtain a user’s IP address.
As a result, only users with whitelisted IP will be able to access our system.
This is a basic implementation, but we can customize our AuthenticationProvider as much as we want using a user’s IP. For example, we can store the IP address with user details on signup and compare it during authentication in our AuthenticationProvider.
6. Conclusion
We learned how to whitelist an IP range in Spring Security using Java and XML configuration. We also learned how to whitelist an IP range by building a custom AuthenticationProvider.
The full source code can be found over on GitHub.