Configuring Spring Boot authentication using In-memory and Database providers

In this tutorial we will learn how to secure Spring Boot Web applications using different security providers from the default Security user/password to In-Memory Security. Finally we will switch to Database authentication using mysql as a database.

Spring Boot Project creation

The starter point is to include the spring-boot-starter-security in your Spring initializr. Start by creating your project as follows:

$ mkdir spring-boot-secure $ cd spring-boot-secure $ spring init -d=web,thymeleaf,data-rest,security -g=com.example -a=spring-boot-secure --package-name=com.example -name=spring-boot-secure -x 

The following list of dependencies will be added in your project:

<?xml version="1.0" encoding="UTF-8"?><project>
   <dependencies>
            
      <dependency>
                
         <groupId>org.springframework.boot</groupId>
                
         <artifactId>spring-boot-starter-data-rest</artifactId>
             
      </dependency>
          
      <dependency>
                
         <groupId>org.springframework.boot</groupId>
                
         <artifactId>spring-boot-starter-security</artifactId>
             
      </dependency>
          
      <dependency>
                
         <groupId>org.springframework.boot</groupId>
                
         <artifactId>spring-boot-starter-thymeleaf</artifactId>
             
      </dependency>
          
      <dependency>
                
         <groupId>org.springframework.boot</groupId>
                
         <artifactId>spring-boot-starter-web</artifactId>
             
      </dependency>
          
      <dependency>
                
         <groupId>org.springframework.boot</groupId>
                
         <artifactId>spring-boot-starter-test</artifactId>
                
         <scope>test</scope>
             
      </dependency>
       
   </dependencies>
    
</project>

The following project tree will be created:

spring-boot-secure/ ├── mvnw ├── mvnw.cmd ├── pom.xml └── src     ├── main     │   ├── java     │   │   └── com     │   │       └── example     │   │           └── SpringBootSecureApplication.java     │   └── resources     │       ├── application.properties     │       ├── static     │       └── templates     └── test         └── java             └── com                 └── example                     └── SpringBootSecureApplicationTests.java 

Next,let’s add a minimal REST Controller to our application to test it:

package com.example;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class SampleController {
  @RequestMapping("/greeting")
  public String greeting() {
    return "Hello world!";
  }
}

Now start our application:

$ ./mvnw spring-boot:run 

As you can see from the logs, a security password has been generated automatically for the default user ‘user’:

Using generated security password: 96172694-a2ef-4fa6-8797-ef5dea54fef5 

Now if you try to reach the /greeting REST Service, a basic authentication window will be displayed:

Spring boot security

If you enter the user name ‘user’ and the password printed on the console, you will be able to reach your REST Service.

Configuring Security in application.properties

Next step, will be adding an user name and password into the application.properties file. This will replace the default user and password:

# Security spring.security.user.password=mypassword spring.security.user.name=myuser 

Restart your application and verify that you are able to login with ‘myuser’ and ‘mypassword’.

In-Memory Security

Using the application.properties file isn’t a real solution. As next step, let’s see how you can use in-memory security. To enable HTTP Security in Spring Boot, we need to extend the WebSecurityConfigurerAdapter and provide a default configuration in the configure(HttpSecurity http) method:

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().authenticated().and().httpBasic();
  }

  @Autowired
  public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication().withUser("user").password("password").roles("USER");
  }
}

We have provide an user with a role in the configureGlobal method. This method is called to auto-wire the AuthenticationManagerBuilder.

The AuthenticationManagerBuilder allows you to easily build your authentication by adding UserDetailsService and the authentication providers. In this case, it will use in-memory because it’s calling the inMemoryAuthentication method and setting up two users with their passwords and roles.

Before running the application, let’s comment the users in application.properties:

# Security  #spring.security.user.password=mypassword #spring.security.user.name=myuser

Now start our application and try to request our REST resource using the “user” and “password” credentials:

$ ./mvnw spring-boot:run 

Database security

The last step will be changing the provider to a database. In order to do that, our example application will require some additional dependencies, assuming that MySQL will be used as database:

$ spring init -d=web,thymeleaf,data-jpa,data-rest,mysql,security -g=com.example -a=spring-boot-secure --package-name=com.example -name=spring-boot-secure -x 

We will use MySQL starting a Docker image of it:

docker run -d  -p 3306:3306 -e MYSQL_USER=spring -e MYSQL_PASSWORD=spring -e MYSQL_DATABASE=mysqlschema -e MYSQL_ROOT_PASSWORD=secret mysql 

Then, we will include the datasource settings in application.properties that will be used to authenticate against the database:

spring.datasource.url = jdbc:mysql://172.17.0.2:3306/mysqlschema spring.datasource.username = spring spring.datasource.password = spring spring.datasource.testWhileIdle = true spring.datasource.validationQuery = SELECT 1 spring.jpa.show-sql = true spring.jpa.hibernate.ddl-auto = create-drop spring.jpa.hibernate.naming-strategy = org.hibernate.cfg.ImprovedNamingStrategy spring.jpa.properties.hibernate.dialect = org.hibernate.dialect.MySQL5Dialect spring.data.rest.basePath

Now let’s connect to our database and define the tables and some users:

create table users(     -> username varchar(50) not null primary key,     -> password varchar(100) not null,     -> enabled boolean not null     -> );  mysql> create table authorities (     -> username varchar(50) not null,     -> authority varchar(50) not null,     -> constraint fk_authorities_users foreign key(username) references users(username)     -> );  mysql> create unique index ix_auth_username on authorities (username,authority);  mysql> insert into users(username,password,enabled)     -> values('admin','$2a$10$.phOScfrUCA7zY5n9CK7cOKNft4HMfwqkVZYUAE1azFeXpK0WcnSa',true);  mysql> insert into authorities(username,authority)      -> values('admin','ROLE_ADMIN');  

As you can see, we have included an encrypted password for the user admin. The password is “admin” and we have encrypted using:

String encoded = new BCryptPasswordEncoder().encode("admin");
System.out.println(encoded);

Now it’s just a matter of changing the Provider used for authentication. In this case, we will use jdbcAuthentication providing the queries to retrieve the username and the role:

package com.example;

import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

@Configuration
@EnableAutoConfiguration
public class DatabaseSecurityConfiguration extends WebSecurityConfigurerAdapter {
  @Autowired DataSource dataSource;

  @Override
  protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.jdbcAuthentication()
        .dataSource(dataSource)
        .usersByUsernameQuery("select username, password, enabled" + " from users where username=?")
        .authoritiesByUsernameQuery(
            "select username, authority " + "from authorities where username=?")
        .passwordEncoder(new BCryptPasswordEncoder());
  }

  @Override
  protected void configure(HttpSecurity http) throws Exception {
    http.authorizeRequests().anyRequest().hasAnyRole("ADMIN", "USER").and().httpBasic();
  }
}

That’s all! Verify that authentication works with the user we have inserted (admin/admin).

Congratulations, you have just completed the Spring Boot authentication using different security combinations from the default Security user/password to In-Memory Security. Finally we will switch to Database authentication using mysql as a database.