Spring Security Configuration - HttpSecurity vs WebSecurity

JavaSpring BootSpring Security

Java Problem Overview


I just need to understand something in Spring Security Configuration. Using the example below...

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .httpBasic()
            .and()
            .authorizeRequests().antMatchers("/secret/**").authenticated()
            .and()
            .authorizeRequests().antMatchers("/**").permitAll();
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/resources/**");
    }

}

What is the purpose of configure(WebSecurity web) method?

Can't I just add /resources/** in the configure(HttpSecurity http) method in this line .authorizeRequests().antMatchers("/**", "/resources/**").permitAll(); Shouldn't it work the same i.e. permitting all requests to /resources/** without any authentication?

Java Solutions


Solution 1 - Java

General use of WebSecurity ignoring() method omits Spring Security and none of Spring Security’s features will be available. WebSecurity is based above HttpSecurity.

@Override
public void configure(WebSecurity web) throws Exception {
    web
        .ignoring()
        .antMatchers("/resources/**")
        .antMatchers("/publics/**");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .authorizeRequests()
        .antMatchers("/admin/**").hasRole("ADMIN")
        .antMatchers("/publics/**").hasRole("USER") // no effect
        .anyRequest().authenticated();
}

WebSecurity in the above example lets Spring ignore /resources/** and /publics/**. Therefore the .antMatchers("/publics/**").hasRole("USER") in HttpSecurity is unconsidered.

> This will omit the request pattern from the security filter chain entirely. Note that anything matching this path will then have no authentication or authorization services applied and will be freely accessible.

configure(HttpSecurity) allows configuration of web-based security at a resource level, based on a selection match - e.g. The example below restricts the URLs that start with /admin/ to users that have ADMIN role, and declares that any other URLs need to be successfully authenticated.

configure(WebSecurity) is used for configuration settings that impact global security (ignore resources, set debug mode, reject requests by implementing a custom firewall definition). For example, the following method would cause any request that starts with /resources/ to be ignored for authentication purposes.


Let's consider the below code, we can ignore the authentication for the endpoint provided within antMatchers using both the methods.

@Override
public void configure(WebSecurity web) throws Exception {
    web
        .ignoring()
        .antMatchers("/login", "/register", "/api/public/**");
}

@Override
public void configure(HttpSecurity http) throws Exception {

    http
        .csrf().disable()
        .authorizeRequests()
        .antMatchers("/login", "/register", "/api/public/**").permitAll()
        .anyRequest().authenticated();
}
  • configure(WebSecurity web) Endpoint used in this method ignores the spring security filters, security features (secure headers, csrf protection etc) are also ignored and no security context will be set and can not protect endpoints for Cross-Site Scripting, XSS attacks, content-sniffing.

  • configure(HttpSecurity http) Endpoint used in this method ignores the authentication for endpoints used in antMatchers and other security features will be in effect such as secure headers, CSRF protection, etc.

Solution 2 - Java

When you use HttpSecurity and try to permitAll() requests. Your requests will be allowed to be accessed from the Spring Security Filter Chain. This is costly as there will be requests other requests which would also come into this filter chain which needs to be allowed or disallowed based on Authentication/Authorization.

HttpSecurity.authorizeRequests().antMatchers("/**", "/resources/**").permitAll();

But when you use, any requests to resources will completely by pass the Spring Security Filter Chain all together. It is safe because you don't need any Authentication/Authorization to be in place to see an image or read a javascript file.

WebSecurity.ignoring().antMatchers("/resources/**");

Solution 3 - Java

configure(HttpSecurity) : It allows configuring web based security for specific http requests. It is used for configuration of web based security at a resource level, based on a selection match.

configure (WebSecurity) : Allows adding RequestMatcher instances that Spring Security should ignore.

Solution 4 - Java

I want to contribute to the great answers by including some code. There are three beans that are super important in Spring Security. based on their types they are DelegatingFilterProxy, FilterChainProxy and SecurityFilterChain.

DelegatingFilterProxy delegates the job of filtering requests to a bean of type FilterChainProxy which its name is springSecurityFilterChain, and FilterChainProxy is configured like this:

@Bean(
    name = {"springSecurityFilterChain"}
)
public Filter springSecurityFilterChain() throws Exception {
    boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();
    if (!hasConfigurers) {
        WebSecurityConfigurerAdapter adapter = (WebSecurityConfigurerAdapter)this.objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {
        });
        this.webSecurity.apply(adapter);
    }

    return (Filter)this.webSecurity.build();
}

springSecurityFilterChain (or FilterChainProxy) itself has a list of SecurityFilterChain. SecurityFilterChain itself has a list of Filter instances that do the actual logic.

Every time we extend WebSecurityConfigurerAdapter and override the configure(HttpSecurity httpSecurity) method, we actually created a SecurityFilterChain that is going to be used by springSecurityFilterChain

How springSecurityFilterChain selects the appropriate SecurityFilterChain from the list? based on the boolean matches(HttpServletRequest request) method that is defined in the SecurityFilterChain interface.

So HttpSecurity is used to create a customized SecurityFilterChain.

Now when WebSecurity actually comes into play? WebSecurity actually allow us to customize springSecurityFilterChain(or FilterChainProxy). take a look at how springSecurityFilterChain is created.

It is the performBuild method of WebSecurity that is called for creating springSecurityFilterChain bean.

@Override
protected Filter performBuild() throws Exception {
	Assert.state(
			!securityFilterChainBuilders.isEmpty(),
			() -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
					+ "Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
					+ "More advanced users can invoke "
					+ WebSecurity.class.getSimpleName()
					+ ".addSecurityFilterChainBuilder directly");
	int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
	List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
			chainSize);
	for (RequestMatcher ignoredRequest : ignoredRequests) {
		securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
	}
	for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
		securityFilterChains.add(securityFilterChainBuilder.build());
	}
	FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
	if (httpFirewall != null) {
		filterChainProxy.setFirewall(httpFirewall);
	}
	filterChainProxy.afterPropertiesSet();

	Filter result = filterChainProxy;
	if (debugEnabled) {
		logger.warn("\n\n"
				+ "********************************************************************\n"
				+ "**********        Security debugging is enabled.       *************\n"
				+ "**********    This may include sensitive information.  *************\n"
				+ "**********      Do not use in a production system!     *************\n"
				+ "********************************************************************\n\n");
		result = new DebugFilter(filterChainProxy);
	}
	postBuildAction.run();
	return result;
}

As you can see when Spring wants to registers SecurityFilterChain into springSecurityFilterChain bean for each web.ignoring().... Spring is going to add a DefaultSecurityFilterChain which is a custom implementation of SecurityFilterChain into the beginning of the list.

When a request comes along springSecurityFilterChain is going to check its list of SecurityFilterChain in order to delegate the filtering job to that SecurityFilterChain. springSecurityFilterChain is going to call match method of each SecurityFilterChain. if the request URL starts with "/resources/**" in your case Spring delegates the job of filtering request to an instance of DefaultSecurityFilterChain in the beginning of the list and our custom SecurityFilterChains which is added by this line:

for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
	securityFilterChains.add(securityFilterChainBuilder.build());
}

completely ignored.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKihatsView Question on Stackoverflow
Solution 1 - JavaRomil PatelView Answer on Stackoverflow
Solution 2 - JavashazinView Answer on Stackoverflow
Solution 3 - Javaadiraju uttejView Answer on Stackoverflow
Solution 4 - Javahatef alipoorView Answer on Stackoverflow