WebSecurityConfigurerAdapter

WebSecurityConfigurerAdapter is used to customize the security configuration of the application. It is an abstract class offered by Spring Security.
By overriding its techniques, it offers a practical means to set security rules and policies.
This class serves as the foundation for extending WebSecurityConfigurerAdapter-based configuration classes.
In this article, we will understand this class and how it can be used to customize a spring application.

Configuring WebSecurityConfigurerAdapter

To customize the security of your application, you need to create a class and extend WebSecurityConfigurerAdapter in order to setup Spring Security using this adapter.
Extending this class will provide numerous methods that can be overridden to specify security rules.
To make the Spring Security capabilities available, this class must be annotated with @EnableWebSecurity.

A basic configuration class that extends WebSecurityConfigurerAdapter is shown here as an example

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        // Configure security rules here
    }
}

Overriding Default Configurations

You can alter the default security configurations by extending WebSecurityConfigurerAdapter and overriding its configure() method.
With configure() method that takes HttpSecurity as argument, you can control which requests should require authentication, which ones should be allowed without being authenticated, and so on.
You can also create security rules based on URL patterns, HTTP methods, and other factors.

The example that follows shows how to permit access to specific URLs without authentication

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

In this example, any request starting with /allow/ will be permitted without authentication, while all other requests will require authentication.

Implementing Custom Authentication

To provide unique authentication procedures, use configure() method of WebSecurityConfigurerAdapter having AuthenticationManagerBuilder argument.
In-memory authentication, JDBC-based authentication, and custom userDetailsService are just a few of the authentication providers that can be configured by overriding this function.
You have complete control over how users are authorized in your application by using custom authentication.

Here is an illustration showing how to set up in-memory authentication

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
        .withUser("user").password("{noop}password").roles("USER")
        .and()
        .withUser("admin").password("{noop}password").roles("ADMIN");
}

In the above example, we configure two users with their passwords and roles.
The {noop} prefix indicates that the passwords are stored in plain text for simplicity. In a production environment, passwords should be properly hashed and secured.

Enabling Method Level Security

Apart from securing URLs, You can secure specific methods within your application with Spring Security.
You can limit access to particular methods based on user roles or other criteria by utilizing method-level security.
To enable method-level security, use @EnableGlobalMethodSecurity annotation with prePostEnabled option set to true over a class that extends WebSecurityConfigurerAdapter.

Here is an illustration showing how to activate method-level security

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

    // Other configurations...
}

By enabling prePostEnabled, you can use annotations like @PreAuthorize and @PostAuthorize to define method-level security rules as shown below

@Service
public class ProductService {

    @PreAuthorize("hasRole('ROLE_ADMIN')")
    public void deleteProduct(Long productId) {
        // Delete product logic
    }
    
    @PostAuthorize("returnObject.owner == authentication.name")
    public Product getProduct(Long productId) {
        // Retrieve product logic
        return product;
    }
    
    // Other methods
}

In this example, the deleteProduct() method is annotated with @PreAuthorize("hasRole('ROLE_ADMIN')"), which ensures that only users with the ROLE_ADMIN role can execute this method.
Similarly, the getProduct() method is annotated with @PostAuthorize("returnObject.owner == authentication.name"), which ensures that the returned product’s owner matches the authenticated user’s name.

Configuring Form Login

One popular authentication method used in online applications is form-based authentication. For your Spring application, form login may be easily configured using WebSecurityConfigurerAdapter.
You can provide the login page, the URL used for the login processing, and other relevant options by overriding the configure(HttpSecurity http) method and utilizing the formLogin() method.

Here is an illustration showing how to set up form login

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .formLogin()
            .loginPage("/login")
            .loginProcessingUrl("/authenticate")
            .defaultSuccessUrl("/home")
            .permitAll()
        .and()
        .authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated();
}

In this example, we configure the login page URL, the URL for processing the login request, and the default success URL after successful authentication.
permitAll() method allows access to the login page without authentication.

With Spring Security you can also control forbidden access when a user tries to access a resource for which they do not have the necessary permissions.
To specify how access forbidden scenarios should be handled, use the configure(HttpSecurity http) method provided by WebSecurityConfigurerAdapter.
To handle access refused scenarios, you can modify the access denied page, redirect URLs, or even use custom logic.

Here is an illustration of how to deal with access denied

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .exceptionHandling()
            .accessDeniedPage("/access-denied")
            .and()
        .authorizeRequests()
            .antMatchers("/admin/**").hasRole("ADMIN")
            .anyRequest().authenticated();
}

In this example, we configure the access denied page URL to /access-denied.
If a user tries to access a restricted resource without sufficient privileges, they will be redirected to this page.

Securing RESTful APIs

Spring Security also allows you to secure RESTful APIs in addition to standard web applications.
By specifying the authentication criteria, turning on CSRF protection, and managing authentication failures, the WebSecurityConfigurerAdapter enables you to setup security for RESTful endpoints.
The antMatchers() method allows you to specify URL patterns for protecting your APIs.

An illustration of how to protect RESTful APIs is provided here

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

In this example, we disable CSRF protection because it is not required for stateless RESTful APIs.
The antMatchers() method secures all requests that begin with /api/ and needs authentication.
Other requests are not required to be authenticated.
For added convenience, we offer HTTP Basic authentication.

Remember Me authentication is a useful feature that keeps users logged in even after they close their browser.
You may easily activate and setup Remember Me authentication for your application using WebSecurityConfigurerAdapter.

You can provide the token validity, remember-me parameter name, and other options by modifying the configure(HttpSecurity http) method and using the rememberMe() method.

Here’s an example of how to enable Remember Me authentication

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .rememberMe()
            .key("uniqueAndSecretKey")
            .rememberMeParameter("remember-me")
            .rememberMeCookieName("remember-me-cookie")
            .tokenValiditySeconds(86400);
}

In this example, we configure Remember Me authentication with a unique and secret key, specify the remember-me parameter name as remember-me, set the cookie name to remember-me-cookie, and set the token validity to 24 hours (86400 seconds).
Integrating with OAuth2

OAuth2 is a very common authorization and authentication protocol.
You can secure your application with OAuth2 providers such as Google, Facebook, and GitHub thanks to Spring Security.
You can define OAuth2 client details, redirect URLs, and other particular parameters for OAuth2 integration by using WebSecurityConfigurerAdapter.

Below example shows how to use Spring Security to seamlessly integrate your application with OAuth2.

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .oauth2Login()
                .loginPage("/login")
                .defaultSuccessUrl("/home")
                .failureUrl("/login-error")
                .and()
            .authorizeRequests()
                .antMatchers("/home").authenticated()
                .anyRequest().permitAll();
    }
}

In this example, we configure OAuth2 login with a custom login page, default success URL, and failure URL. The antMatchers() method is used to secure the /home page and requires authentication.
Securing Websockets

If your application utilizes Websockets for real-time communication, you may secure them as well.
WebSecurityConfigurerAdapter lets you configure Websocket security by overriding the configure(HttpSecurity http) method and using the websocket() method.
You can establish Websocket security rules, enable message-level security, and manage Websocket connection authentication.

Here’s a simple example of how to protect Websockets

@Configuration
@EnableWebSocketMessageBroker
public class WebSocketSecurityConfig extends AbstractSecurityWebSocketMessageBrokerConfigurer {
    
    @Override
    protected void configureInbound(MessageSecurityMetadataSourceRegistry messages) {
        messages
            .simpDestMatchers("/secured/**").authenticated()
            .anyMessage().permitAll();
    }
    
    // Other configuration options here
}

In this example, we configure security for Websockets and restrict access to the “/secured/” destination to authenticated users. All other messages are permitted without authentication.

Conclusion

We explored the role of WebSecurityConfigurerAdapter in configuring security for Spring applications in this post.
We looked about how to use its different methods to configure security rules, build custom authentication techniques, secure RESTful APIs, and integrate with OAuth2.
You can ensure that your Spring-based apps are secure by following best practices and harnessing the capability of WebSecurityConfigurerAdapter.