'Spring security - How to whitelist localhost?

I am trying to set set an OAuth2 security system with client_credentials and a JWT token for a Spring boot api. I am using postman to test its functionality. So, there is a controller that does some basic things like GET Status request or GET tables of an entity request. The API works as intented when there is no security at all. It works perfectly when I am using a GET request with OAuth2 authentication through Postman as well.

Now, I am trying to whitelist some IPs so when I am using the API from the localhost IP there is no need for authentication and all the resources are public but when somebody with a different IP tries to access it, then he needs to authenticate. The problem is, no matter what I do in the WebSecurityConfiguration.java on HttpSecurity configuration, Postman returns that I am unauthorized unless I authenticate with client_credentials.

What I have tried:

  • http.authorizeRequests().antMatchers("/**").permitAll();
  • http.authorizeRequests().antMatchers("/**").hasIpAddress("::1").anyRequest().permitAll();
  • http.authorizeRequests().antMatchers("/**").hasIpAddress("127.0.0.1").anyRequest().permitAll();
  • http.authorizeRequests().anyRequest().access("hasIpAddress('127.0.0.1') or isAuthenticated()");
  • http.authorizeRequests().anyRequest().permitAll();

and some more combinations. Nothing works of the above. What do I do wrong and how can I grant public access to localhost but make other/external IPs to require authentication? Maybe I am testing it wrong from Postman?(I am changing Authentication from OAuth2 to NoAuth or Inherit from parent).

I would like to note that web.ignoring().antMatchers("/**"); on WebSecurity configuration works fine and removes authentication from all my resources.

WebSecurityConfiguration.java

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {

@Autowired
private UsersService usersService;

@Bean
public PasswordEncoder encoder() {
    return new BCryptPasswordEncoder();
}

@Override
@Autowired
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.userDetailsService(usersService).passwordEncoder(encoder());
}
@Override
public void configure(WebSecurity web) throws Exception {
    web.ignoring();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
            .antMatchers("/**")
            .hasIpAddress("127.0.0.1")
            .anyRequest().permitAll()
        .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.IF_REQUIRED);
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}
}

ConfigOAuth2.java

@Configuration
public class ConfigOAuth2 extends AuthorizationServerConfigurerAdapter{

@Value("test")
private String clientId;
@Value("test-key")
private String clientSecret;

private String privateKey = "-----BEGIN RSA PRIVATE KEY-----\n" +
        "MIIEogIBAAKCAQEArOyEna4QGVfHs2uLkspnvg990DoG8LsTRVWUln6PNnzHdciU\n" +
        "wbTWa3Mmvnas3fH+ryAB+w3hgcRHH5D0SQzZG8JgcSnUDi4nxdjhcrdxeAMeeEKP\n" +
        "mWZPhUzmuNS5j1ZjRoLo/ih4PNssXdjy1w35h5qtrBTI3JrEkBMBQMkfHuWeK1EV\n" +
        "CCdP5krHl2Nf0vKG0MQVnU+FKbLzZtM3hryHTFMWHUAAijJ///nlimfU3Xdju4Nw\n" +
        "TIktaP1FWhUhSoNy0xVGYQVx3XlT2AG9mQeZWTmC8Vbw2X5BMXg1A0H/Rt55Vpf0\n" +
        "+HB4ZsMxRzvYWe6Xgf1+SCWH8O0mIS5DFohgfQIDAQABAoIBAENGjV2vL5I8hXQ3\n" +
        "XgjQ+EWIT2FogfS8Q4YRAor+WAdRymP3knA+Q8Fv/l3RW/XJRVWqtTqQLvDGhQkx\n" +
        "4uhcuEbFe7HrHRYbPNwLQcLYvat8Qyl0c9uxYzSwM38rO7oZWOxA2Baxdf3vIzar\n" +
        "xeaHCFKKihDN0UuKZvjKfA1RcesZtH9U4kZFJGZsAOvFkqvXKDA5G0CGqJJbDHuA\n" +
        "uBNIk7ggy+wsyLaGEWkj49IdYZhhMbkWaNKbYPi5zK7Wz54N/qi+HQl0tVQKXw4e\n" +
        "oJl24ua1IIhoHIS+ipX1pJVy4MKGh6gZizzl+9MvOzgp81APVPa6obpE2oT5XPAe\n" +
        "ovIRMh0CgYEA2WPwRSiHv0Sc/9g9dpK4M7tk+njoqdcn5oYMikWtMcqlGNhZbh2s\n" +
        "sQmB03354BArE5KQ4KA8tGzWVNXnf2k+8klNdlz+Q/GxS0G1E4aqkl4Dq/EfVif+\n" +
        "mb2gUccpXQ4ygFDmjP5tx7cqHNytYMYJ6rKPOA0GfqWS5XkPTMIZDB8CgYEAy6LT\n" +
        "yd4py19MNtsgLwR4F8A+/ffvCy9TRHnpAlYgzeTVW3LHN4j/3DQ25g/AOFsrx/1A\n" +
        "GBTq6g8SDSe4qDoRmaRPPVmVtwuVE9uH/F83vlz5LvMJqQCbOMMcJZc/lApP9fGM\n" +
        "yRKlvSyrrjialMFHiFU5HasyRArdQCE48jTJP+MCgYAuSHHCN6PXHAOVEPPdB9XB\n" +
        "5dbU4OMgLden48hNtBHwtOU7iexYXmcC9jQ20+5cPvT84MqJmHP0Mevb+gKkhMLL\n" +
        "EMI2PgxAaPfHPwEPXC96pBuCAv8Z97/j+ZRldNKgpkIoQZEkWZMD30JPDMi4/tDj\n" +
        "sAp/8337fsLsqj6QqA5vHwKBgHAUW6sk+y3zcrhSnQEj3ZF8/267Urd+Qb9TthrS\n" +
        "GtYYGBJwNxPq9KBXoMu5aZvbGlrFmcxnXvCagN36udjltSAyXmau8wc/ebrnPo56\n" +
        "Pe0psQDVRcDeE5EHWmuaNqUdk+sTGuDkwZJAjvGiN/qd8ugnt/sLaewnaqVMY9Jz\n" +
        "mTzvAoGAUKMucO57do5xYFezmCvrzaLhlQZi+3fBHlrribUEkdmJNC4Q4FGPcysS\n" +
        "TkcgVs0m7xgbubkn+yjuEVFsojWAPeJBIUnCbpDTIUDRARpbOCxgdVTdzIl3ACxc\n" +
        "r9q0DV3XIQ4SKYIUmgc2sFSrTEjEaisDLpZVMLZZaJQldXQfeFM=\n" +
        "-----END RSA PRIVATE KEY-----";


private String publicKey = "-----BEGIN PUBLIC KEY-----\n" +
        "MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArOyEna4QGVfHs2uLkspn\n" +
        "vg990DoG8LsTRVWUln6PNnzHdciUwbTWa3Mmvnas3fH+ryAB+w3hgcRHH5D0SQzZ\n" +
        "G8JgcSnUDi4nxdjhcrdxeAMeeEKPmWZPhUzmuNS5j1ZjRoLo/ih4PNssXdjy1w35\n" +
        "h5qtrBTI3JrEkBMBQMkfHuWeK1EVCCdP5krHl2Nf0vKG0MQVnU+FKbLzZtM3hryH\n" +
        "TFMWHUAAijJ///nlimfU3Xdju4NwTIktaP1FWhUhSoNy0xVGYQVx3XlT2AG9mQeZ\n" +
        "WTmC8Vbw2X5BMXg1A0H/Rt55Vpf0+HB4ZsMxRzvYWe6Xgf1+SCWH8O0mIS5DFohg\n" +
        "fQIDAQAB\n" +
        "-----END PUBLIC KEY-----";

@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;

@Autowired
PasswordEncoder passwordEncoder;

@Bean
public JwtAccessTokenConverter tokenEnhancer() {
    JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
    converter.setSigningKey(privateKey);
    converter.setVerifierKey(publicKey);
    return converter;
}

@Bean
public JwtTokenStore tokenStore() {
    return new JwtTokenStore(tokenEnhancer());
}

@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    endpoints.authenticationManager(authenticationManager).tokenStore(tokenStore())
            .accessTokenConverter(tokenEnhancer());
}
@Override
public void configure(AuthorizationServerSecurityConfigurer security) throws Exception {
    security.tokenKeyAccess("permitAll()").checkTokenAccess("isAuthenticated()");
}
@Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
    clients.inMemory()
            .withClient(clientId)
                .secret(passwordEncoder.encode(clientSecret))
                .scopes("read", "write")
                .authorizedGrantTypes("client_credentials")
                .accessTokenValiditySeconds(2000)
                .refreshTokenValiditySeconds(200000);
}
}

DEBUG logs

13:57:13.024 INFO  org.springframework.data.repository.config.RepositoryConfigurationDelegate.registerRepositoriesIn() @132 - Bootstrapping Spring Data JPA repositories in DEFAULT mode.
13:57:13.034 INFO  org.springframework.data.repository.config.RepositoryConfigurationDelegate.registerRepositoriesIn() @201 - Finished Spring Data repository scanning in 7 ms. Found 0 JPA repository interfaces.
13:57:13.523 INFO  org.springframework.boot.web.embedded.tomcat.TomcatWebServer.initialize() @108 - Tomcat initialized with port(s): 9090 (http)
13:57:13.618 INFO  org.springframework.boot.web.servlet.context.ServletWebServerApplicationContext.prepareWebApplicationContext() @290 - Root WebApplicationContext: initialization completed in 1195 ms
13:57:13.958 INFO  org.springframework.boot.autoconfigure.h2.H2ConsoleAutoConfiguration.logDataSources() @89 - H2 console available at '/h2-console'. Database available at 'jdbc:mysql://172.16.69.19:3306/SpringRestApi'
13:57:14.568 INFO  org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean.buildNativeEntityManagerFactory() @437 - Initialized JPA EntityManagerFactory for persistence unit 'default'
13:57:14.668 WARN  org.springframework.boot.autoconfigure.orm.jpa.JpaBaseConfiguration$JpaWebConfiguration.openEntityManagerInViewInterceptor() @219 - spring.jpa.open-in-view is enabled by default. Therefore, database queries may be performed during view rendering. Explicitly configure spring.jpa.open-in-view to disable this warning
13:57:14.883 INFO  org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter.setSigningKey() @178 - Configured with RSA signing key
13:57:14.893 INFO  org.springframework.security.oauth2.provider.token.store.JwtAccessTokenConverter.afterPropertiesSet() @309 - Signing and verification RSA keys match
13:57:15.003 DEBUG org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$2.performBuild() @225 - No authenticationProviders and no parentAuthenticationManager defined. Returning null.
13:57:15.083 DEBUG org.springframework.security.oauth2.provider.endpoint.FrameworkEndpointHandlerMapping.handlerMethodsInitialized() @367 - 8 mappings in 'oauth2EndpointHandlerMapping'
13:57:15.155 DEBUG org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource.process() @72 - Adding web access control expression [fullyAuthenticated] for Ant [pattern='/oauth/token']
13:57:15.155 DEBUG org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource.process() @72 - Adding web access control expression [permitAll()] for Ant [pattern='/oauth/token_key']
13:57:15.155 DEBUG org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource.process() @72 - Adding web access control expression [isAuthenticated()] for Ant [pattern='/oauth/check_token']
13:57:15.165 INFO  org.springframework.security.web.DefaultSecurityFilterChain.<init>() @55 - Will secure Or [Ant [pattern='/oauth/token'], Ant [pattern='/oauth/token_key'], Ant [pattern='/oauth/check_token']] with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@1715471a, org.springframework.security.web.context.SecurityContextPersistenceFilter@39c4ff6a, org.springframework.security.web.header.HeaderWriterFilter@1dd2b124, org.springframework.security.web.authentication.logout.LogoutFilter@276931c8, org.springframework.security.web.authentication.www.BasicAuthenticationFilter@25ac2e09, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@5b3977b, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@7a22601a, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@4d9e81ea, org.springframework.security.web.session.SessionManagementFilter@65b44c8, org.springframework.security.web.access.ExceptionTranslationFilter@1202c487, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@1884a702]
13:57:15.175 DEBUG org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource.process() @72 - Adding web access control expression [authenticated] for any request
13:57:15.175 INFO  org.springframework.security.web.DefaultSecurityFilterChain.<init>() @55 - Will secure org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfiguration$NotOAuthRequestMatcher@4405cf2c with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@47946ba1, org.springframework.security.web.context.SecurityContextPersistenceFilter@5f1bd95b, org.springframework.security.web.header.HeaderWriterFilter@c603be5, org.springframework.security.web.authentication.logout.LogoutFilter@21acfb59, org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter@a2e077c, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@3bdde833, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@36ef43be, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@6a642abc, org.springframework.security.web.session.SessionManagementFilter@79fdff10, org.springframework.security.web.access.ExceptionTranslationFilter@54a61083, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@3f9718de]
13:57:15.195 DEBUG org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource.process() @72 - Adding web access control expression [hasIpAddress('127.0.0.1') or hasIpAddress('::1') or isAuthenticated()] for Ant [pattern='/**']
13:57:15.195 DEBUG org.springframework.security.web.access.expression.ExpressionBasedFilterInvocationSecurityMetadataSource.process() @72 - Adding web access control expression [authenticated] for any request
13:57:15.195 INFO  org.springframework.security.web.DefaultSecurityFilterChain.<init>() @55 - Will secure any request with [org.springframework.security.web.context.request.async.WebAsyncManagerIntegrationFilter@2d8aabe8, org.springframework.security.web.context.SecurityContextPersistenceFilter@f20d544, org.springframework.security.web.header.HeaderWriterFilter@5cbdfc31, org.springframework.security.web.csrf.CsrfFilter@7e8a74cc, org.springframework.security.web.authentication.logout.LogoutFilter@cf83769, org.springframework.security.web.savedrequest.RequestCacheAwareFilter@1d584e6b, org.springframework.security.web.servletapi.SecurityContextHolderAwareRequestFilter@2eb77585, org.springframework.security.web.authentication.AnonymousAuthenticationFilter@20e8f0e6, org.springframework.security.web.session.SessionManagementFilter@6b5817fb, org.springframework.security.web.access.ExceptionTranslationFilter@4fabb82b, org.springframework.security.web.access.intercept.FilterSecurityInterceptor@facdff6]
13:57:15.195 WARN  org.springframework.security.config.annotation.web.builders.WebSecurity.performBuild() @322 - 

********************************************************************
**********        Security debugging is enabled.       *************
**********    This may include sensitive information.  *************
**********      Do not use in a production system!     *************
********************************************************************


13:57:16.196 INFO  org.springframework.boot.devtools.autoconfigure.OptionalLiveReloadServer.startServer() @58 - LiveReload server is running on port 35729
13:57:16.206 INFO  org.springframework.boot.actuate.endpoint.web.EndpointLinksResolver.<init>() @58 - Exposing 1 endpoint(s) beneath base path '/actuator'
13:57:16.282 INFO  org.springframework.boot.web.embedded.tomcat.TomcatWebServer.start() @220 - Tomcat started on port(s): 9090 (http) with context path '/api/v1.0'
13:57:16.292 INFO  gr.daem.springrestgeneric.SpringRestGenericApplication.logStarted() @61 - Started SpringRestGenericApplication in 4.092 seconds (JVM running for 4.675)
13:57:16.411 INFO  org.springframework.web.servlet.DispatcherServlet.initServletBean() @525 - Initializing Servlet 'dispatcherServlet'
13:57:16.411 INFO  org.springframework.web.servlet.DispatcherServlet.initServletBean() @547 - Completed initialization in 0 ms
13:57:18.390 INFO  Spring Security Debugger.info() @56 - 

************************************************************

Request received for GET '/generic/status':

org.apache.catalina.connector.RequestFacade@57ece8c5

servletPath:/generic/status
pathInfo:null
headers: 
user-agent: PostmanRuntime/7.29.0
accept: */*
cache-control: no-cache
postman-token: 5cf5e7b5-a4fe-4fb7-b420-91bec32d580c
host: localhost:9090
accept-encoding: gzip, deflate, br
connection: keep-alive


Security filter chain: [
  WebAsyncManagerIntegrationFilter
  SecurityContextPersistenceFilter
  HeaderWriterFilter
  LogoutFilter
  OAuth2AuthenticationProcessingFilter
  RequestCacheAwareFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  SessionManagementFilter
  ExceptionTranslationFilter
  FilterSecurityInterceptor
]


************************************************************


13:57:18.393 DEBUG org.springframework.security.web.FilterChainProxy.doFilterInternal() @208 - Securing GET /generic/status
13:57:18.394 DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter() @102 - Set SecurityContextHolder to empty SecurityContext
13:57:18.395 DEBUG org.springframework.security.oauth2.provider.authentication.BearerTokenExtractor.extractToken() @54 - Token not found in headers. Trying request parameters.
13:57:18.395 DEBUG org.springframework.security.oauth2.provider.authentication.BearerTokenExtractor.extractToken() @57 - Token not found in request parameters.  Not an OAuth2 request.
13:57:18.395 DEBUG org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationProcessingFilter.doFilter() @141 - No token in request, will continue chain.
13:57:18.396 DEBUG org.springframework.security.web.authentication.AnonymousAuthenticationFilter.doFilter() @100 - Set SecurityContextHolder to anonymous SecurityContext
13:57:18.398 DEBUG org.springframework.security.web.access.intercept.FilterSecurityInterceptor.attemptAuthorization() @247 - Failed to authorize filter invocation [GET /generic/status] with attributes [#oauth2.throwOnError(authenticated)]
13:57:18.414 DEBUG org.springframework.security.oauth2.provider.error.DefaultOAuth2ExceptionRenderer.writeWithMessageConverters() @101 - Written [error="unauthorized", error_description="Full authentication is required to access this resource"] as "application/json" using [org.springframework.http.converter.json.MappingJackson2HttpMessageConverter@7b42bf94]
13:57:18.415 DEBUG org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter() @118 - Cleared SecurityContextHolder to complete request


Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source