Kotlin Spring Security Custom Login

Spring Security provides a custom login page that is functional but not very attractive. In most cases, web developers want a more attractive looking login page. This post demonstrates how to configure Spring Security to use a custom login page. Readers can view this tutorial for a demonstration on how to configure basic Spring Security.

Front End—Write a Custom Page

We are going to start by writing a custom login page. Spring Security is very flexible about the page itself, but there are a few rules that need to be followed.

  • Form requires Username
  • Form requires Password
  • CSRF Token is required

This is a screen shot of the page that will be used for this tutorial.
LoginPage
Followed by the code.
LoginCode
It’s critical to remember to include the CSRF token in the form. Without it, the server will refuse any HTTP POST requests and will respond with code 405. The th:name="${_csrf.parameterName}" th:value="${_csrf.token}" on an input take will do the job of adding the CSRF token.

Backend—Configure Spring

Once the front end code is ready, you need to configure Spring Security to use this page. In order to render the login page, Spring will need some sort of controller class. Developers are free to write their own, but it’s also trivial to make use of the one Spring is happy to provide.

@Configuration
class WebConfig : WebMvcConfigurerAdapter() {
    override fun addViewControllers(registry: ViewControllerRegistry) {
        //This class adds a default controller for the login page.
        //Otherwise you would need to write a custom controller class
        registry.addViewController("/login").setViewName("login")
    }
}

The next job is to configure Spring security.

@Configuration //Make this as a configuration class
@EnableWebSecurity //Turn on Web Security
class SecurityWebInitializer : WebSecurityConfigurerAdapter(){
    override fun configure(http: HttpSecurity) {
        http
                .authorizeRequests()
                    //We need to allow anonymous users to
                    //access the login page (otherwise we get 403)
                    .antMatchers("/login").anonymous()
                    .anyRequest().authenticated()
                .and()
                    //Setup a custom login page
                    .formLogin()
                        .loginPage("/login")
                        .usernameParameter("username")
                        .passwordParameter("password")
                .and()
                    .httpBasic()
    }

    override fun configure(auth: AuthenticationManagerBuilder) {
        //This code sets up a user store in memory. This is
        //useful for debugging and development
        auth
                .inMemoryAuthentication()
                    .withUser("bob")
                    .password("belcher")
                    .roles("USER")
                .and()
                    .withUser("admin")
                    .password("admin")
                    .roles("USER", "ADMIN")
    }
}

It’s important to allow anonymous() access to the login page. Without it, Spring Security will continue to redirect to the login page until the server returns 403 (too many redirects).

Conclusion

Once complete, the site will render a custom login page like what is shown in the video.


You can get the code for the complete project at my GitHub page.

Spring Security Form Login with JDBC – Kotlin

Spring Security makes it really simple to authenticate users against a database. This tutorial builds on the previous tutorial of configuring Spring Security to secure web applications.

Database Schema

Spring Security is happy to do all of the work of querying a database and validating user information provided your database conforms to the correct database schema (note, you are free to customize). Here is the sql script that is used to configure an example datasource for this project that is based of the one provided in the Spring documetation.

/* See https://docs.spring.io/spring-security/site/docs/current/reference/html/appendix-schema.html */

DROP TABLE IF EXISTS persistent_logins;
DROP TABLE IF EXISTS group_members;
DROP TABLE IF EXISTS group_authorities;
DROP TABLE IF EXISTS groups;
DROP TABLE IF EXISTS authorities;
DROP TABLE IF EXISTS users;

create table users(
  username varchar_ignorecase(50) not null primary key,
  password varchar_ignorecase(50) not null,
  enabled boolean not null
);

create table authorities (
  username varchar_ignorecase(50) not null,
  authority varchar_ignorecase(50) not null,
  constraint fk_authorities_users foreign key(username) references users(username)
);

create unique index ix_auth_username on authorities (username,authority);

create table groups (
  id bigint generated by default as identity(start with 0) primary key,
  group_name varchar_ignorecase(50) not null
);

create table group_authorities (
  group_id bigint not null,
  authority varchar(50) not null,
  constraint fk_group_authorities_group foreign key(group_id) references groups(id)
);

create table group_members (
  id bigint generated by default as identity(start with 0) primary key,
  username varchar(50) not null,
  group_id bigint not null,
  constraint fk_group_members_group foreign key(group_id) references groups(id)
);

create table persistent_logins (
  username varchar(64) not null,
  series varchar(64) primary key,
  token varchar(64) not null,
  last_used timestamp not null
);

insert into users values('bob_belcher', 'burger_bob', true);
insert into authorities values ('bob_belcher', 'user');

This script drops all tables if they exist and then recreates the database tables. It also populates the database with a user: bob_belcher. Creating and destroying the DB in this fashion is useful for both development purposes and unit testing. Naturally, a production machine would preserve the data each time.

Spring Configuration

Configuring Spring Security to work with our database is a complete breeze at this point. We start by creating two bean definitions for both a data source and a jdbcTemplate.

@Configuration
class DataConfig {

    @Bean(name = arrayOf("dataSource"))
    fun dataSource() : DataSource {
        //This will create a new embedded database and run the schema.sql script
        return EmbeddedDatabaseBuilder()
                .setType(EmbeddedDatabaseType.HSQL)
                .addScript("schema.sql")
                .build()
    }

    @Bean
    fun jdbcTemplate(@Qualifier("dataSource") dataSource: DataSource) : JdbcOperations {
        return JdbcTemplate(dataSource)
    }
}

Since I am using Spring Boot, I did qualify our dataSource bean so that the container knew which bean I wanted to use for our datasource.

Now that we have our data source configured, we just need to tell Spring Security about it. It’s not very difficult.

@Configuration //Make this as a configuration class
@EnableWebSecurity //Turn on Web Security
class SecurityWebInitializer(
        //Inject our datasource into this class for the AuthenticationManagerBuilder
        @Autowired @Qualifier("dataSource") val dataSource: DataSource)
    : WebSecurityConfigurerAdapter(){

    override fun configure(http: HttpSecurity) {
        http
                    .formLogin()
                .and()
                    .logout()
                        .logoutSuccessUrl("/")
                .and()
                    .rememberMe()
                        .tokenRepository(JdbcTokenRepositoryImpl())
                            .tokenValiditySeconds(2419200)
                                .key("BurgerBob")
                .and()
                    .httpBasic()
                .and()
                    .authorizeRequests()
                        .antMatchers("/").authenticated()
                        .anyRequest().permitAll()
    }

    override fun configure(auth: AuthenticationManagerBuilder) {
        //As long as our database schema conforms to the default queries
        //we can use jdbcAuthentication and pass in our data source
        //Spring will do the rest of the work for us
        auth.jdbcAuthentication().dataSource(dataSource)
    }
}

In this case, all that is needed is to call auth.jdbcAuthentication().dataSource and pass in our dataSource object. Spring Security takes it from there.

Conclusion

Here is a video of this in action.


You can grab the entire code from my Github page here.

Kotlin Spring Security Tutorial

Just about anybody can appreciate the value of securing a web application. After all, who would do their online banking on an unsecured website? Of course, it’s not just online banking that requires security. Just about any website that has information that requires protecting needs security.

Spring provides web security modules that help us secure our applications. As with everything in Spring, it’s really easy to use an configure.

Define a Security Class

Spring has us extend the WebSecurityConfigurerAdapter class and annotate it with @Configuration and @EnableWebSecurity. Here is an example Kotlin class that enables our web security and forces all requests to the web application to be authenticated.

@Configuration //Make this as a configuration class
@EnableWebSecurity //Turn on Web Security
class SecurityWebInitializer : WebSecurityConfigurerAdapter(){
    override fun configure(http: HttpSecurity) {
        //This tells Spring Security to authorize all requests
        //We use formLogin and httpBasic
        http
                .authorizeRequests()
                    .anyRequest()
                    .authenticated()
                .and()
                    .formLogin()
                .and()
                    .httpBasic()
    }

    override fun configure(auth: AuthenticationManagerBuilder) {
        //This code sets up a user store in memory. This is
        //useful for debugging and development
        auth
                .inMemoryAuthentication()
                    .withUser("bob")
                    .password("belcher")
                    .roles("USER")
                .and()
                    .withUser("admin")
                    .password("admin")
                    .roles("USER", "ADMIN")
    }
}

The first method, configure(http: HttpSecurity) calls methods on the http object. This class has a chaining interface and by calling the proper methods, we can tailor the security configuration to suit our needs. The methods are plain english, so the code ends up being highly self-documenting.

The other configure method accepts an auth: AuthenticationManagerBuild. The auth object is used to configure a data store for users. For the purposes of this post, we are creating an inMemoryAuthentication. This is useful for development and debugging purposes.

The Controller Class

There isn’t anything special about the controller class. That’s a feature of Spring Security. Security is a cross cutting concern which means that the main application code should not have to concern itself with security. Instead, Spring uses Aspect Orientated programming to secure our application.

Sometimes it’s useful to know what user is logged into this system. There is a an example of how to access this information and pass it back to the view. (Readers who are not familiar with Spring MVC can refer here for an example of Spring MVC).

@Controller
@RequestMapping("/")
class IndexController {

    @RequestMapping(method = arrayOf(RequestMethod.GET))
    fun doGet(model : Model) : String {
        //We can access the current user like this
        val authorization = SecurityContextHolder.getContext().authentication

        //Send the user name back to the view
        model.addAttribute("username", authorization.name)
        return "index"
    }
}

The SecurityContextHolder class provides an access point to the current logged in user. Spring calls it an authentication. The object returns contains information about the user such as the user name.

Conclusion

Here is a video of logging into this site in action.


You can get the code from my github page here.

Spring Bean Validation Example (JSR-303) in Kotlin

Many developers need a solution to validating forms. Spring MVC supports bean validation (JSR-303) which is an easy to use annotation driven framework that is used to validate objects. Spring utilizes bean validation throughout the entire application framework, allowing developers to annotation one or more objects and ensure they are valid from the controller all the way to the data access layer.

Since Kotlin is compatible with Java libraries, this post demonstrates how to use bean validation along with Spring MVC to validate a user registration form. Here is a screen shot of the form we are going to validate.
WelcomeScreen copy

Step 1—Define a Form Object

We will use a POJO that carries data from the view to the server. Kotlin makes this really easy because it provides data classes.

data class User(@get: NotBlank (message = "{first_name.required}")
                    var firstName : String = "",

                @get: NotBlank (message = "{last_name.required}")
                    var lastName : String = "",

                @get: NotBlank (message="{email.required}")
                @get: Email (message = "{email.invalid}")
                    var email : String = "",

                @get: NotBlank (message="{phone.required}")
                    var phone : String = "",

                @get: NotBlank (message="{address.required}")
                    var address : String = "",

                @get: NotBlank (message="{city.required}")
                    var city : String = "",

                @get: NotBlank (message="{state.required}")
                @get: Size(min=2, max=2, message = "{state.size}")
                    var state : String = "",

                @get: NotBlank (message="{zip.required}")
                    var zip : String = "")

You will notice a couple of things in the class. The first is the @get [annotation] annotation. Kotlin generates getter/setter methods in the Java bytecode. When we use the @get annotation followed by the annotation, Kotlin will place the target annotation on the getter method. So for example, @get: NotBlank is telling the Kotlin compiler to place the @NotBlank annotation on the generated getter method.

Next you will notice the message argument that is passed to the NotBlank annotation. In the first example, we have message = “{first_name.required}”. The message parameter takes a String that is displayed to the user when validation fails. If we use expression language, Spring boot will look for a ValidationMessages.properties file that contains the actual message. This is useful when making localized applications because you can have a different ValidationMessages file per language.

In this example, we are using three different Hibernate Validator annotations.

  • NotBlank—Valid if a String is not blank. Fails is the String is blank or null.
  • Email—Valid if the string field contains a valid email address
  • Size—Valid if the string has at least min number of characters and less than max characters

Step 2—ValidationMessages.properties

If you choose to use a ValidationMessages.properties file, Spring Boot will look for the actual message inside of a ValidationMessages.properties file in the applications classpath. I find this to be the preferred approach because it allows develoeprs to easily localize an application if needed. Here is the properties file we are using in this example.

first_name.required="First name is required"
last_name.required="Last name is required"
email.required="Please enter your email address"
email.invalid="Please provide a valid email address"
phone.required="Please enter a phone number"
address.required="Please enter your address"
city.required="Please enter a city"
state.required="Please enter a state"
state.size="Please use 2 letter state code"
zip.required="Enter a zip code"

The keys of the file are the same as when is passed to the message parameter of each bean validator annotation. The value is what is ultimately displayed to the user.

Step 3-Controller

Spring MVC uses a controller class. Here is the code for our controller in this example.

@Controller
@RequestMapping("/")
@Scope(WebApplicationContext.SCOPE_REQUEST)
class ValidatorController(@Autowired val registrationService: RegistrationService) {

    @RequestMapping(method = arrayOf(RequestMethod.GET))
    fun doGet(model : Model) : String {
        model.addAttribute("user", User())
        return "index"
    }

    @RequestMapping(method = arrayOf(RequestMethod.POST))
    fun doPost(@Valid user : User,  //The @Valid annotation tells Spring to Validate this object
               errors : Errors)  //Spring injects this class into this method. It will hold any
                                //errors that are found on the object
            : String {
        val result : String
        when {
            //Test for errors
            errors.hasErrors() -> result = "index"
            else -> {
                //Otherwise proceed to the next page
                registrationService.user = user
                result = "redirect:/congrats"
            }
        }
        return result
    }
}

The first method is doGet which is mapped to an HTTP Get request. Nothing fancy here for those readers who are famailier with Spring MVC (This post explains Spring MVC for users who are not famalier with Spring MVC). All we do here is create a new instance of the User class and pass it to the view.

The doPost is the method that we care about for this post. This method has two parameters. The first one is a User argument that is annotated with @Valid. The other one is an Errors object. These two argument work in tandem to validate a Spring MVC form.

The User object is bound to the web form. Each field in the form is mapped to a property on the User class. When the form is submitted, Spring MVC carries this object from the View to the Controller. However, if the parameter has the @Valid annotation, then the User object make a stop and is examaned by a class that impelements javax.validation.Validator. Should the validation report any errors, they are gathered together in the Errors object that is injected into this method.

The errors.hasErrors() method returns true if the user entered invalid input into the form. We can return the name of the page that was submitted and report the errors back to the user if that is the case. Here is what it looks like.
Invalid copy

On the other hand, we can redirect the user to the next page if everything is ok (errors.hasErrors() == false).
Congrats copy

Step 4—The View

Of course, we need to setup our web page properly in order to actually see the errors. Since I am a big fan of Twitter’s Bootstrap, I use their form validation framework to make a nice front-end display to the errors message.

Here is a code snippet of a field on the form.
field
We use a teneray expression to check each field if it has errors th:class="${#fields.hasErrors('firstName') ?'form-group has-error' : 'form-group'}". If the field has an error, we use bootstraps has-error css class to get the red outline. Otherwise, we don’t add that class and just use form-group. In case you are wondering, the fields object is the same Errors object that we were using in our server code. This is just another rendition of the same object.

The next thing to do is print out each error. This can be done very easily by using the th:each tag and assigning each message to the err variable: th:each="err: ${#fields.errors('firstName')}" class="help-block" th:text="${err}". When executed, this code will look up the message (found in ValidationMessages.properties) for each error and write is out to a span tag.

When run, each field that has an error will have its textbox outlined and the error message printed below the text box.

Getting the Code

You can get the complete code for this project at my github page.

Result

Here is the final result

Kotlin Spring MVC

Kotlin makes Spring MVC projects a total breeze. This is a simple web application that combines a few different Kotlin techniques into a Spring Boot project. Here are few screen shots of the finished example and then we will dive into the code that makes it possible.

 

package com.stonesoupprogramming.kotlinspringmvc

import org.springframework.boot.SpringApplication
import org.springframework.boot.autoconfigure.SpringBootApplication
import org.springframework.stereotype.Controller
import org.springframework.ui.Model
import org.springframework.web.bind.annotation.RequestMapping
import org.springframework.web.bind.annotation.RequestMethod

@SpringBootApplication //This performs magic under the hood to launch a spring web application
class KotlinSpringMvcHelloWorldApplication

//Entry point to the application
fun main(args: Array) {
    SpringApplication.run(KotlinSpringMvcHelloWorldApplication::class.java, *args)
}

//This is a class that we are using for our form
//Kotlin let's us one line it!
data class Registration(var firstName: String = "", var lastName: String = "")

@Controller //Tells Spring this is a controller class
@RequestMapping("/") //Tells Spring to handle web requests at the root
class Controller {

    //This function will handle HTTP Get Requests
    @RequestMapping(method = arrayOf(RequestMethod.GET))
    fun doIndexGet(model: Model): String{
        //Send a new instance of Registration back to the view
        model.addAttribute("registration", Registration())

        //Render the index.html page
        return "index"
    }

    //This method handles HTTP Post
    @RequestMapping(method = arrayOf(RequestMethod.POST))
    fun doIndexPost(formParams: Registration, model: Model): String {
        //Send a greeting message to the view
        model.addAttribute("greet", "Hello ${formParams.firstName} ${formParams.lastName}")

        //Render the greet.html page
        return "greet"
    }

    //This handles GET requests for /greet.html
    @RequestMapping(path = arrayOf("/greet"), method=arrayOf(RequestMethod.GET))
    fun doGreetGet(): String = "greet" //Just tell it to render the greet.html page
}

Initializing the Application

Many readers are no doubt familiar with Spring Boot. Our first class in this project appears on line 11 with this code.

@SpringBootApplication //This performs magic under the hood to launch a spring web application
class KotlinSpringMvcHelloWorldApplication

Kotlin focuses on begin concise and in this is literally an empty class that is annotated with @SpringBootApplication. The annotation performs some Spring magic that does the job of initializing the Spring environment for us. Our next segment of code is the entry point to the application.

//Entry point to the application
fun main(args: Array) {
    SpringApplication.run(KotlinSpringMvcHelloWorldApplication::class.java, *args)
}

Once again, there isn’t much code here, but a lot is happening under the hood that is invisible to us. We are calling the static SpringApplication.run function and passing into it the KotlinSpringMvcHelloWorldApplication class along with the supplied command line arguments. Once again, we will leave it up to Spring to prepare our environment.

Data Class

Many Java developers have no doubt made classes the are simply holders for properties along with a constructor, getters and setters, hashcode(), equals(), and toString(). Two common applications of such classes are ORM model classes and classes that can be passed back to the view. In this case we are making a class that gets passed to the view, but we are going to define it using Kotlin’s data class. The code for such a class is extremely brief.

data class Registration(var firstName: String = "", var lastName: String = "")

Using this single line of code, we make a Registration class with two properties, a default constructor, and an overloaded constructor. The class comes packed with hashcode(), equals(), toString() and when used in Java code, it will have getters and setters. We are going to pass this code back to the view in the controller class.

Controller

The Controller is another portion of Spring MVC. We use it to map HTTP requests to the appropriate methods in the class. Spring will also inject a Model class when needed so that we can pass data back to the view. Here is the controller class written in Kotlin.

@Controller //Tells Spring this is a controller class
@RequestMapping("/") //Tells Spring to handle web requests at the root
class Controller {

    //This function will handle HTTP Get Requests
    @RequestMapping(method = arrayOf(RequestMethod.GET))
    fun doIndexGet(model: Model): String{
        //Send a new instance of Registration back to the view
        model.addAttribute("registration", Registration())

        //Render the index.html page
        return "index"
    }

    //This method handles HTTP Post
    @RequestMapping(method = arrayOf(RequestMethod.POST))
    fun doIndexPost(formParams: Registration, model: Model): String {
        //Send a greeting message to the view
        model.addAttribute("greet", "Hello ${formParams.firstName} ${formParams.lastName}")

        //Render the greet.html page
        return "greet"
    }

    //This handles GET requests for /greet.html
    @RequestMapping(path = arrayOf("/greet"), method=arrayOf(RequestMethod.GET))
    fun doGreetGet(): String = "greet" //Just tell it to render the greet.html page
}

The first line is the @Controller annotation. Our Spring boot environment has component scanning enabled, so we only need to annotate our controller class to make Spring aware of it’s existence. On line 2, we have the @RequestMapping annotation that tells Spring that the default request mapping for this class is the root of the web application (‘/’). The class contains three functions: doIndexGet, doIndexPost, and doGreetGet. Let’s talk about each in detail.

doIndexGet

This method is annotated with @RequestMapping and it handles HTTP Get requests to the ‘/’ endpoint. The function has one parameter, model : Model, and it returns a String. The model parameter is injected by Spring.

On the first line of the function, we add a “registration” attribute to the model with a new instance of Registration. Notice that in Kotlin, we do not need the new keyword and since we define default arguments for our Regsitration class, we do not need to supply an parameters. The function ends by returning the String “index” which will tell Spring and Thymeleaf (which is our template engine) which page to render.

doIndexPost

This function handles HTTP post methods as indicated by @RequestMapping(method = arrayOf(RequestMethod.POST)). It’s two arguments, formParams: Registration, and model : Model, are injected into this method by Spring. In the view, we have the following http form.
form copy
Inside of this html code you will see things like ${registration}, th:field=”*{firstName}”, and th:field=”*{lastName}”. These special tags map these input fields to the properties our Registration object that we sent back to the view in the doIndexGet function. When we click on the submit button the setter methods of the registration object are called and the values of the input boxes in the form are inserted into Registration::firstName and Registration::lastName. Then the Registration object is sent back to the server and routed to our doIndexPost method.

Once we are inside of the doIndexPost method, we can add a String to our model class.

model.addAttribute("greet", "Hello ${formParams.firstName} ${formParams.lastName}")

The second argument is the portion that I wish to discuss. Kotlin has String templating which lets us build a String using inline variables. Thus the ${formParams.firstName} will get replaced with the first name entered by the user and ${formParams.lastName} gets replaced with the last name the user entered. Then the function returns with the String “greet” which tells the web application to show the greet page.

doGreetGet

This final function is the shortest. It’s simply a function that handles the request mapping for HTTP Get when the browser navigates to the greet page. However, Kotlin let’s us define functions inline, so it’s worth talking about.

@RequestMapping(path = arrayOf("/greet"), method=arrayOf(RequestMethod.GET))
fun doGreetGet(): String = "greet" //Just tell it to render the greet.html page

All this code does is return the string “greet” so that the web application knows to render the greet.html page. Since it’s literally just returning one value, we can legally write String = “greet” in Kotlin and omit the method body.

Web Pages

For reference purposes, I have included screen shots of the web pages (they don’t seem to render properly when I use the code formatter 😦 sorry readers)!

index.html

index copy
We have already discussed how the Registration object is bound to the html form on this page. However, it’s worth pointing out that this page uses Bootstrap for page layout. Most of the code in this page was auto-generated by Intellij also, which has world class support for Bootstrap.

greeting.html

greet_page copy
This is the other page that get’s returned by the controller after the user enters their name. We built a String in doPostIndex and mapped it to the key “greet” in the model. On this page, we can show that custom greeting by using th:text=”${greet}”. The template engine is smart enough to insert this greeting between the header tags.

Source

You can get the complete source code for this project from my Bitbucket page. Happy coding!