Spring Security Basic Authentication

1. Overview

This tutorial will explain how to set up, configure, and customize Basic Authentication with Spring. We’re going to build on top of the simple Spring MVC example, and secure the UI of the MVC application with the Basic Auth mechanism provided by Spring Security.

2. The Spring Security Configuration

We can configure Spring Security using Java config:

@Configuration
@EnableWebSecurity
public class CustomWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {

    @Autowired
    private MyBasicAuthenticationEntryPoint authenticationEntryPoint;

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
          .withUser("user1").password(passwordEncoder().encode("user1Pass"))
          .authorities("ROLE_USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
          .antMatchers("/securityNone").permitAll()
          .anyRequest().authenticated()
          .and()
          .httpBasic()
          .authenticationEntryPoint(authenticationEntryPoint);

        http.addFilterAfter(new CustomFilter(),
          BasicAuthenticationFilter.class);
    }

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

Here we’re using the httpBasic() element to define Basic Authentication inside the configure() method of a class that extends WebSecurityConfigurerAdapter.

We could achieve the same result using XML as well:

[prismatic_encoded class=%%language-xml%%]Jmx0O2h0dHAgcGF0dGVybj0iL3NlY3VyaXR5Tm9uZSIgc2VjdXJpdHk9Im5vbmUiLyZndDsNCiZsdDtodHRwIHVzZS1leHByZXNzaW9ucz0idHJ1ZSImZ3Q7DQogICAgJmx0O2ludGVyY2VwdC11cmwgcGF0dGVybj0iLyoqIiBhY2Nlc3M9ImlzQXV0aGVudGljYXRlZCgpIiAvJmd0Ow0KICAgICZsdDtodHRwLWJhc2ljIC8mZ3Q7DQombHQ7L2h0dHAmZ3Q7DQoNCiZsdDthdXRoZW50aWNhdGlvbi1tYW5hZ2VyJmd0Ow0KICAgICZsdDthdXRoZW50aWNhdGlvbi1wcm92aWRlciZndDsNCiAgICAgICAgJmx0O3VzZXItc2VydmljZSZndDsNCiAgICAgICAgICAgICZsdDt1c2VyIG5hbWU9InVzZXIxIiBwYXNzd29yZD0ie25vb3B9dXNlcjFQYXNzIiBhdXRob3JpdGllcz0iUk9MRV9VU0VSIiAvJmd0Ow0KICAgICAgICAmbHQ7L3VzZXItc2VydmljZSZndDsNCiAgICAmbHQ7L2F1dGhlbnRpY2F0aW9uLXByb3ZpZGVyJmd0Ow0KJmx0Oy9hdXRoZW50aWNhdGlvbi1tYW5hZ2VyJmd0Ow==[/prismatic_encoded]

What’s relevant here is the <http-basic> element inside the main <http> element of the configuration. This is enough to enable Basic Authentication for the entire application. Since we’re not focusing on the Authentication Manager in this tutorial, we’ll use an in-memory manager with the user and password defined in plain text.

The web.xml of the web application enabling Spring Security has already been discussed in the Spring Logout tutorial.

3. Consuming the Secured Application

The curl command is our go-to tool for consuming the secured application.

First, let’s try to request the /homepage.html without providing any security credentials:

curl -i http://localhost:8080/spring-security-rest-basic-auth/api/foos/1

We get back the expected 401 Unauthorized and the Authentication Challenge:

HTTP/1.1 401 Unauthorized
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=E5A8D3C16B65A0A007CFAACAEEE6916B; Path=/spring-security-mvc-basic-auth/; HttpOnly
WWW-Authenticate: Basic realm="Spring Security Application"
Content-Type: text/html;charset=utf-8
Content-Length: 1061
Date: Wed, 29 May 2013 15:14:08 GMT

Normally the browser would interpret this challenge and prompt us for credentials with a simple dialog, but since we’re using curl, this isn’t the case.

Now let’s request the same resource, the homepage, but provide the credentials to access it as well:

curl -i --user user1:user1Pass 
  http://localhost:8080/spring-security-rest-basic-auth/api/foos/1

As a result, the response from the server is 200 OK along with a Cookie:

HTTP/1.1 200 OK
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=301225C7AE7C74B0892887389996785D; Path=/spring-security-mvc-basic-auth/; HttpOnly
Content-Type: text/html;charset=ISO-8859-1
Content-Language: en-US
Content-Length: 90
Date: Wed, 29 May 2013 15:19:38 GMT

From the browser, we can consume the application normally; the only difference is that a login page is no longer a hard requirement since all browsers support Basic Authentication, and use a dialog to prompt the user for credentials.

4. Further Configuration – the Entry Point

By default, the BasicAuthenticationEntryPoint provisioned by Spring Security returns a full page for a 401 Unauthorized response back to the client. This HTML representation of the error renders well in a browser. Conversely, it’s not well suited for other scenarios, such as a REST API where a json representation may be preferred.

The namespace is flexible enough for this new requirement as well.  To address this, the entry point can be overridden:

<http-basic entry-point-ref="myBasicAuthenticationEntryPoint" />

The new entry point is defined as a standard bean:

@Component
public class MyBasicAuthenticationEntryPoint extends BasicAuthenticationEntryPoint {

    @Override
    public void commence(
      HttpServletRequest request, HttpServletResponse response, AuthenticationException authEx) 
      throws IOException, ServletException {
        response.addHeader("WWW-Authenticate", "Basic realm="" + getRealmName() + """);
        response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
        PrintWriter writer = response.getWriter();
        writer.println("HTTP Status 401 - " + authEx.getMessage());
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        setRealmName("VietMX");
        super.afterPropertiesSet();
    }
}

By writing directly to the HTTP Response, we now have full control over the format of the response body.

5. The Maven Dependencies

The Maven dependencies for Spring Security have been discussed before in the Spring Security with Maven article. We will need both spring-security-web and spring-security-config available at runtime.

6. Conclusion

In this article, we secured an MVC application with Spring Security and Basic Authentication. We discussed the XML configuration, and we consumed the application with simple curl commands. Finally, we took control of the exact error message format, moving from the standard HTML error page to a custom text or JSON format.

The full implementation of this article can be found in the GitHub project. This is a Maven-based project, so it should be easy to import and run as it is.

When the project runs locally, the sample HTML can be accessed at:

http://localhost:8080/spring-security-rest-basic-auth/api/foos/1.

Related posts:

Filtering a Stream of Optionals in Java
Hướng dẫn sử dụng Java String, StringBuffer và StringBuilder
Default Password Encoder in Spring Security 5
Spring Security – security none, filters none, access permitAll
Java Program to Implement Hash Tables chaining with Singly Linked Lists
Spring MVC and the @ModelAttribute Annotation
Join and Split Arrays and Collections in Java
Java Program to Implement Unrolled Linked List
Implementing a Runnable vs Extending a Thread
So sánh HashMap và HashSet trong Java
Tìm hiểu cơ chế Lazy Evaluation của Stream trong Java 8
Java Program to Implement ConcurrentLinkedQueue API
Sorting in Java
Mix plain text and HTML content in a mail
Map Serialization and Deserialization with Jackson
Java Program to Implement Flood Fill Algorithm
Java Copy Constructor
Java Program to Represent Graph Using Adjacency List
Hướng dẫn sử dụng Lớp FilePermission trong java
The Spring @Controller and @RestController Annotations
Java Program to Find a Good Feedback Vertex Set
Java Program to Perform Cryptography Using Transposition Technique
Guide to Java 8 groupingBy Collector
Java Program to Apply Above-Below-on Test to Find the Position of a Point with respect to a Line
Java Program to Implement Meldable Heap
Java Program to Implement SimpeBindings API
Spring WebClient Filters
Java Program to Implement Weight Balanced Tree
Java Convenience Factory Methods for Collections
Stack Memory and Heap Space in Java
Từ khóa throw và throws trong Java
Kiểu dữ liệu Ngày Giờ (Date Time) trong java