Enable Spring security using kotlin!!

spring boot

Spring security is the defacto abstraction in the spring framework world to add authentication and authorization layer for your application. There are plenty of examples. In this article, we have spring security using kotlin.

In the last article, we have seen that and developed Spring Boot, MongoDB REST API using kotlin. We will use the same example to add spring security dependency.

https://github.com/maheshwarLigade/springboot-mongodb.restapi/tree/master

To illustrate spring-security example add spring security starter dependency.

implementation("org.springframework.boot:spring-boot-starter-security")

If you are in favor of the Maven build tool then use below dependency.

<dependency> 
<groupId>org.springframework.boot</groupId> 
<artifactId>spring-boot-starter-security</artifactId> 
</dependency>

As our existing example of REST API using kotlin. it contains patient data and CRUD operation so we will have two different roles, ADMIN and Doctor. 

For simplification, we will have two roles only and we will only one endpoint “\patients” with five different operations. We will secure all our end point either using @Secured annotation or config class.

import org.springframework.context.annotation.Bean
import org.springframework.context.annotation.Configuration
import org.springframework.http.HttpMethod
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
import org.springframework.security.crypto.password.PasswordEncoder

@Configuration
class SecurityConfig : WebSecurityConfigurerAdapter() {

    @Bean
    fun encoder(): PasswordEncoder {
        return BCryptPasswordEncoder()
    }

    override fun configure(auth: AuthenticationManagerBuilder) {
        auth.inMemoryAuthentication()
                .withUser("admin")
                .password(encoder().encode("pass"))
                .roles("DOCTOR", "ADMIN")
                .and()
                .withUser("doctor")
                .password(encoder().encode("pass"))
                .roles("DOCTOR")
    }

    @Throws(Exception::class)
    override fun configure(http: HttpSecurity) {
        http.httpBasic()
                .and()
                .authorizeRequests()
                .antMatchers(HttpMethod.GET, "/patients").hasRole("ADMIN")
                .antMatchers(HttpMethod.POST, "/patients/**").hasRole("ADMIN")
                .antMatchers(HttpMethod.PUT, "/patients/**").hasRole("ADMIN")
                .antMatchers(HttpMethod.DELETE, "/patients/**").hasRole("ADMIN")
                .antMatchers(HttpMethod.GET, "/patients/**").hasAnyRole("ADMIN", "DOCTOR")
                .and()
                .csrf().disable()
                .formLogin().disable()
    }

}

As we have five operations and two roles ADMIN and DOCTOR.

If you don’t want to encrypt the password you can use a plain text password with {noop} prefix.

First step where we have declared two users and then which endpoints do we want to secure and https method those we have configured. 

In this example we have two get endpoints first one to get all records of patients and another one is a specific patient record. This is a very good use case because 

  1. Get ALL patient only admin can access
  2. Get a particular patient that endpoint is accessible DOCTOR who treats him/her and ADMIN as well who has access to everything. 

csrf().disable is about disabling Spring Security built-in cross-site scripting protection.

formLogin().disable() is about disabling default login form.

Now everything is ready we have secured our REST endpoint. Let us hit all the REST endpoints in a previous way, you will get 401/403 HTTP status code. Try using the CURL command. 

$ curl localhost:8090/patients 
{   
"timestamp": "2020-04-12T05:37:16.718+0000",
"status": 401,   
"error": "Unauthorized",   
"message": "Unauthorized",   
"path": "/patients"
}

$ curl localhost:8090/patients -u admin:pass

Use the above endpoint and you will get successful results.

This is it for now about this. I know this is a very simple use case and example too but you can use the same structure and scale that to next level using a database with different user roles and access control lists.

GitHubCode Repo:-

https://github.com/maheshwarLigade/springboot-mongodb.restapi/tree/master