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.

Advertisements

Kotlin Koans—Part 22

More functional programming on the horizon. This portion of Kotlin Koans demonstrated folding. I personally had never tackled a challenge like this so it took me more time to figure it out than the other problems. My job was to go through all customers and the products they ordered and reduce them down to a single set of objects. Here is the Kotlin code.

fun Shop.getSetOfProductsOrderedByEveryCustomer(): Set {
    // Return the set of products ordered by every customer
    return customers.fold(allOrderedProducts, {
        orderedByAll, customer ->
            orderedByAll.intersect(customer.orderedProducts)
    })
}

As usual, I tried to do the same problem in Java for comparison purposes, but I wasn’t able to figure it out! (If you know the solution, please leave it in the comments section!). I’ll have to admit that I am weak in some of the functional programming areas.

You can click here to see Part 21.

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.

Kotlin Koans—Part 21

The Kotlin Koans tutorial continues with more demonstrations about the extensions on collection classes. This portion of the tutorial was a partitioning problem where I had to return the customers that have not had their orders delivered. Here is the code.

fun Shop.getCustomersWithMoreUndeliveredOrdersThanDelivered(): Set {
    // Return customers who have more undelivered orders than delivered
    return customers.partition { it.orders.all { it.isDelivered } }.second.toSet()
}

Kotlin adds a partition method to it’s collection classes. The partition method takes a lambda expression that returns a boolean. Inside of this lambda, I used the all (#TODO Link to All) method on the orders collection. Once again, I am returning a boolean value.

Now for the coolest part. Kotlin has a pair class that has a first and second method. Since I need the orders that are not delievered, I use the second property on the Pair class. At this point, second is holding a collection of Customers whose orders are not delivered. Finally, I can use the toSet (#TODO Link) method to transform the collection into a set.

Like the last few portions of this tutorial, I decided to compare the Kotlin code to the Java 8 code. Here is what I came up with.

public static Set getCustomersWithMoreUndeliveredOrdersThanDelivered(Shop shop){
    return new HashSet(shop.getCustomers()
            .stream()
            .collect(Collectors.partitioningBy((Customer c) -> c.getOrders().stream().allMatch(Order::isDelivered)))
            .get(false));
}

You can click here to see Part 20.

Kotlin Koans—Part 20

Grouping objects by a property and storing them into a map is a challenge that all developers have faced at some point in time. For example, you may have a collection of Customers and you wish to find out which Customers live in each city. Basically, you want a map where City is the key and a Collection of Customers associated with that City is the value.

This was exactly the problem that Kotlin Koans tutorial had me do.

fun Shop.groupCustomersByCity(): Map {
    // Return a map of the customers living in each city
    return customers.groupBy { it.city }
}

I was able to arrange all of the Customers by city with just one line of Kotlin code. The related Java code wasn’t that difficult either, but I did have to search for the solution since it wasn’t quite as clear as the Kotlin approach.

public static Map groupCustomersByCity(Shop shop){
    return shop.getCustomers().stream().collect(Collectors.groupingBy(Customer::getCity));
}

What helped me with the Kotlin approach was that since the groupBy method was direclty on the Collection object, my IDE was able to supply me with the groupBy method. That’s not the case with the Java approach since it’s using a static method on the Collectors class. It also didn’t occur to me to use the collect method on the Stream object either. I was looking for something that said group in it.

You can click here to see Part 19.

Kotlin Koans—Part 19

This section of the Kotlin Koans tutorial continued onward with Kotlin’s collection API enhancement. The challenge in this section use to total the price of all products a customer purchased. Here is the code

fun Customer.getTotalOrderPrice(): Double {
    // Return the sum of prices of all products that a customer has ordered.
    // Note: a customer may order the same product for several times.
    return orders.sumByDouble { it.products.sumByDouble { it.price } }
}

The collection API in Kotlin has a sumByDouble method, which takes a lambda expression. The lambda let’s developers chain function calls. In this case, each Customer had a collection of Products in each Order. To get the price of all Products ordered, I needed the sum of the price of all products in a order. This was easy enough to do because I just made a nested call to sumByDouble on it.products and then told it to sum on it.price.

Here is Java code that solves the same problem.

public static double getTotalOrderPrice(Customer customer){
    return customer
            .getOrders()
            .stream()
            .mapToDouble(
                    order -> order.getProducts()
                                    .stream()
                                    .mapToDouble(Product::getPrice)
                            .sum())
            .sum();
}

You can click here to see Part 18