Build a Spring-Boot REST service with Basic Authentication for several users

This post describes how to build a REST service with Spring-Boot that uses Basic-Authentication for several users and that uses the username of the authenticated user to do it’s work. Warning: A service using basic authentication should always use HTTPS as transport protocol, either by running behind a web server proxy or by setting up HTTPS by itself. I’ll cover the latter in a later post.

This might be a setup for a service, where for each user, data is stored in a database, so it not only is necessary to authenticate the user to use the service, but it is also necessary in the service to know which user is accessing the service.

The source code for this project can be found at GitHub. The coce relevant for this post is tagged post-20150728.

Setting up the project

I use IntelliJ IDEA (EAP Version 15 with Spring support) for the project and a maven project setup.

To create the initial project, I use Spring Initializr from within IDEA, but you can use https://start.spring.io as well to create the project. I named the project SecuRest, the initial dependencies are Core/Security and Web/Web:

Bildschirmfoto 2015-07-28 um 13.13.57

The created pom.xml looks like this:

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
  <modelVersion>4.0.0</modelVersion>

  <groupId>com.sothawo</groupId>
  <artifactId>securest</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>SecuRest</name>
  <description>Demo project for Spring Boot with Basic Authentication and HTTPS</description>

  <parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.5.RELEASE</version>
    <relativePath/> <!-- lookup parent from repository -->
  </parent>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    <java.version>1.8</java.version>
  </properties>

  <dependencies>
    <dependency>
      <groupId>org.springframework.boot</groupId>
      <artifactId>spring-boot-starter-security</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>
  
  <build>
    <plugins>
      <plugin>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-maven-plugin</artifactId>
      </plugin>
    </plugins>
  </build>
  

</project>

The Service

The first version of the implemented service just has one method which echoes it’s call arguments back:

/**
 * Copyright (c) 2015 sothawo
 *
 * http://www.sothawo.com
 */
package com.sothawo.securest;

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

/**
 * Sample service.
 *
 * @author P.J. Meisch (pj.meisch@sothawo.com).
 */
@RestController
@RequestMapping("/service")
public class UserService {

    @RequestMapping(value = "/echo/{in}", method = RequestMethod.GET)
    public String echo(@PathVariable(value = "in") final String in) {
        return "You said: " + in;
    }
}

There is nothing yet to retrieve the name of the current user, we’ll do that later.

Running the application with the basic setup

This is all that is needed for the first basic application sceleton. When the application ist started, Spring-Boot sets up the security so that the whole application is secured and can only be accessed by a user user; the password is displayed on application startup in the log in a line like this (the password changes each time the application starts). This is the basic behaviour of Spring-Boot when spring-boot-starter-security is found on application startup.

Using default security password: e482e82e-1115-4fc4-86e4-bdcc432da039

When trying to access the application without passing in a username and password, the following result is returned:

curl localhost:8080/service/echo/hello
{"timestamp":1438088762118,"status":401,"error":"Unauthorized","message":"Full authentication is required to access this resource","path":"/service/echo/hello"}

With curl I can pass in the username and password like this:

curl user:e482e82e-1115-4fc4-86e4-bdcc432da039@localhost:8080/service/echo/hello
You said: hello

As an alternative I use IntelliJ’s REST Tool to create an authorization header for the user user and password e482e82e-1115-4fc4-86e4-bdcc432da039 and pass it along with the request:

curl -H "Authorization: Basic dXNlcjplNDgyZTgyZS0xMTE1LTRmYzQtODZlNC1iZGNjNDMyZGEwMzk=" localhost:8080/service/echo/hello
You said: hello

So now access to the service is granted. But, as I said, there is only one user named user allowed, and the password changes every time on application startup. Next, I’ll set up some users with passwords.

 

Setting up the Users

I am using the most basic form to setup different users, and that is by using an in-memory user store. To have that I add the following configuration class:

/**
 * Copyright (c) 2015 sothawo
 *
 * http://www.sothawo.com
 */
package com.sothawo.securest;

import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

/**
 * Security configuration.
 *
 * @author P.J. Meisch (pj.meisch@sothawo.com).
 */
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user1").password("secret1").roles("USER")
                .and()
                .withUser("user2").password("secret2").roles("USER");
    }
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests().anyRequest().fullyAuthenticated();
        http.httpBasic();
        http.csrf().disable();
    }
}

This configuration class configures two users with their passwords and roles. And although when starting the application, a password for the default user user is shown in the log, that user no longer can access the application, only the new configured two users can.

By using @EnableWebMvcSecurity and not @EnableWebSecurity the application has access to the current user in the following way:

/**
 * Sample service.
 *
 * @author P.J. Meisch (pj.meisch@sothawo.com).
 */
@RestController
@RequestMapping("/service")
public class UserService {

    @RequestMapping(value = "/echo/{in}", method = RequestMethod.GET)
    public String echo(@PathVariable(value = "in") final String in, @AuthenticationPrincipal final UserDetails user) {
        return "Hello " + user.getUsername() + ", you said: " + in;
    }
}

After restarting the application the service gives the following result:

curl user1:secret1@localhost:8080/service/echo/hello
Hello user1, you said: hello

So our service is protected by username and passwords and has access to the name of the current user.

Notice: As written at the beginning of this post, it is necessary to use HTTPS transport. This is covered in a later post.

Using Spring-Boot configuration properties in your own classes

When writing a Spring-Boot application it is possible to use your own custom configuration classes which are injected by spring into your application and which  are configured in the application.properties file. There is even support for autocomplete support in the properties file editor in IntelliJ IDEA (I suppose there is something similar in Eclipse or NetBeans, but I haven’t tried that). This post shows how to achieve this.

Basically this is used for auto configuration of Spring-Boot components, but can be used in the Spring-Boot application as well.

The configuration class

Let’s assume we have a class named Support which represents our configuration:

/**
 * Copyright (c) 2015 sothawo
 *
 * http://www.sothawo.com
 */
package com.sothawo.sbconfig;

import org.springframework.boot.context.properties.ConfigurationProperties;

/**
 * @author P.J. Meisch (pj.meisch@sothawo.com).
 */
@Component
@ConfigurationProperties(prefix = "support")
public class Support {

    private Integer productId;

    private Contact contact;


    public Contact getContact() {
        return contact;
    }

    public void setContact(Contact contact) {
        this.contact = contact;
    }

    public Integer getProductId() {
        return productId;
    }

    public void setProductId(Integer productId) {
        this.productId = productId;
    }

    @Override
    public String toString() {
        return "Support{" +
                "productId=" + productId +
                ", contact=" + contact +
                '}';
    }

    public static class Contact {

        private String name;

        private String email;

        public String getEmail() {
            return email;
        }

        public void setEmail(String email) {
            this.email = email;
        }

        public String getName() {
            return name;
        }

        public void setName(String name) {
            this.name = name;
        }

        @Override
        public String toString() {
            return "Contact{" +
                    "name='" + name + '\'' +
                    ", email='" + email + '\'' +
                    '}';
        }
    }
}

This is a plain POJO; it contains an inner class, but that is only for the purpose of showing how Spring Boot configures a field that is itself a class. What marks this as a configuration class is the @ConfigurationProperties annotation, which by it’s prefix argument defines the prefix string to use in the properties file.

Edit 2015-09-21: added missing @Component annotation.

Enable the Spring Boot annotation processor

To have the annotation processed it is necessary to add the following dependency to the project’s pom.xml (notice that it’s optional):

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-configuration-processor</artifactId>
    <optional>true</optional>
</dependency>

After compiling the project there is a new file in the target/META-INF directory named spring-configuration-metadata.json. This is needed for autocomplete support, it contains the names, types and class information of the configuration class:

{
  "groups": [
    {
      "name": "support",
      "type": "com.sothawo.sbconfig.Support",
      "sourceType": "com.sothawo.sbconfig.Support"
    },
    {
      "name": "support.contact",
      "type": "com.sothawo.sbconfig.Support$Contact",
      "sourceType": "com.sothawo.sbconfig.Support",
      "sourceMethod": "getContact()"
    }
  ],
  "properties": [
    {
      "name": "support.contact.email",
      "type": "java.lang.String",
      "sourceType": "com.sothawo.sbconfig.Support$Contact"
    },
    {
      "name": "support.contact.name",
      "type": "java.lang.String",
      "sourceType": "com.sothawo.sbconfig.Support$Contact"
    },
    {
      "name": "support.product-id",
      "type": "java.lang.Integer",
      "sourceType": "com.sothawo.sbconfig.Support"
    }
  ]
}

Using the configuration object

The configuration object is used by injecting it in a Spring bean, for example like this:

/**
 * Copyright (c) 2015 sothawo
 *
 * http://www.sothawo.com
 */
package com.sothawo.sbconfig;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;

/**
 * @author P.J. Meisch (pj.meisch@sothawo.com).
 */
@Component
@EnableConfigurationProperties(Support.class)
public class SupportInfo {
    @Autowired(required = false)
    private Support support;

    @PostConstruct
    public void init() {
        if (null == support) {
            System.out.println("no support");
        } else {
            System.out.println(support.toString());
        }
    }
}

Configuring the object

IntelliJ supports editing the application.properties file with code completion:

sbcfg01

This shows the available configuration properties as well as their types and default values (if the fields of the configuration class are initialized with values). The screenshot shows how field names and inner classes are mapped to the corresponding property entries.

Custom theme for a Vaadin – Spring-boot application

Recently I wrote an application based on Vaadin Spring-boot, and when I needed to modify the theme of the application I needed to do some research as how to achieve that. I think that at the time the combination of Vaadin and Spring-boot is still pretty new so that information still must be sought. So in this post I describe the necessary steps.

I use the following versions of different tools:

  • Oracle JDK 1.8.0_45
  • vaadin 7.4.5
  • vaadin-spring-start 1.0.0.beta3
  • spring-boot 1.2.3.RELEASE
  • spring 4.1.6.RELEASE

My IDE is IntelliJ IDEA 14.1.3

Creating the basic application

I create the application project (named vsbt for vaadin spring boot theme) by using the Spring Initializr from within IDEA, but it can be done via the Website https://start.spring.io as well:

vsbt01

For this demo I set up a project with the following properties that has only Vaadin as a dependency:

vsbt02

vsbt03

After finishing the setup I have an IDEA maven project with the basic application class, but still with no UI:

vsbt04

So to have something visible, I add a MainUI class which uses the valo theme and which just inserts a button in the UI. The button is nonfunctional, as this demo is only concerning with theming the UI and not with functionality:

/**
 * Copyright (c) 2015 sothawo
 *
 * http://www.sothawo.com
 */
package org.sothawo.vsbt;

import com.vaadin.annotations.Theme;
import com.vaadin.server.VaadinRequest;
import com.vaadin.spring.annotation.SpringUI;
import com.vaadin.ui.Button;
import com.vaadin.ui.UI;
import com.vaadin.ui.VerticalLayout;

/**
 * @author P.J. Meisch (pj.meisch@sothawo.com).
 */
@Theme("valo")
@SpringUI
public class MainUI extends UI {
    @Override
    protected void init(VaadinRequest vaadinRequest) {
        VerticalLayout layout = new VerticalLayout();
        layout.setSizeFull();
        layout.setMargin(true);
        layout.setSpacing(true);

        layout.addComponent(new Button("This is a button"));

        setContent(layout);
    }
}

Compiling and running the application gives the following result in the browser:

vsbt05

Changing the theme

Now for changing the theme. I want to create a theme named colored where I change some colors. The first step ist to put the theme files (sass files) in the src/main/webapp/VAADIN/themes/colored folder:

vsbt06

 

The styles.scss file:

@import "addons.scss";
@import "colored.scss";

The colored.scss file:

@import "../valo/valo.scss";

@mixin colored {
  @include valo;

  .v-app {
    background-color: red;
  }

  .v-button {
    background-image: none;
    background-color: yellow;
  }
}

@include colored;

I don’t get into the details of sass files here. In the MainUI class the annotation for the theme must be changed to @Theme("colored").

When I now start the program after building the program with the following command:

mvn clean package
cd target
java -jar vsbt-0.0.1-SNAPSHOT.jar

then the browser shows no theme:

vsbt07

The reason for this is that the files that are located under the src/main/webapp directory are not considered when the jar is packaged, this is only done when building a war file. So the first step that needs to be done is to specify this directory as a resource directory in the maven pom.xml:

<build>
  <resources>
    <resource>
      <directory>src/main/resources</directory>
    </resource>
    <resource>
      <directory>src/main/webapp</directory>
    </resource>
  </resources>
  ...
</build>

One might be tempted to move the VAADIN/themes/colored folder to src/main/resources, but there is still a problem to be solved. When building and running the application, the logging output shows an error message like:

un 02, 2015 9:21:14 PM com.vaadin.server.VaadinServlet persistCacheEntry
WARNUNG: Error persisting scss cache /private/var/folders/xw/1zt9sly53_76h29g7067_y700000gp/T/tomcat-docbase.6378846904000133878.8080/VAADIN/themes/colored/styles.scss.cache
java.io.FileNotFoundException: /private/var/folders/xw/1zt9sly53_76h29g7067_y700000gp/T/tomcat-docbase.6378846904000133878.8080/VAADIN/themes/colored/styles.scss.cache (No such file or directory)
        at java.io.FileOutputStream.open0(Native Method)

This happens because the sass compiler – at least on my Mac – has problems with persisting the compiled css file. To remove that error it is necessary to add the sass compiler to the compile step in the maven pom.xml (and this is the reason to leave the files in the src/main/webapp directory, it’s there that the compiler searches for them):

<dependencies>
        <dependency>
            <groupId>com.vaadin</groupId>
            <artifactId>vaadin-themes</artifactId>
        </dependency>
</dependencies>
...
<plugins>
    <plugin>
        <groupId>com.vaadin</groupId>
        <artifactId>vaadin-maven-plugin</artifactId>
        <executions>
            <execution>
                <goals>
                    <goal>update-theme</goal>
                    <goal>compile-theme</goal>
                    <!--
                    <goal>clean</goal>
                    <goal>resources</goal>
                    <goal>update-widgetset</goal>
                    <goal>compile</goal>
                    -->
                </goals>
            </execution>
        </executions>
    </plugin>
</plugins>

When now compiling the project, the addons.scss and the colored.css files are created in the theme directory and packaged in the application, and after packaging and running, the browser shows the following application with no more logged errors:

vsbt08

I hope this post can help if somebody needs to theme a vaadin spring-boot application and has the same problems finding out where to put the files and how to compile them.