Chapter 6. Securing Your Application

In this chapter, we'll learn how to secure our web application and also how to cope with the security challenges of modern, distributed web applications.

This chapter will be broken up into five parts:

  • First, we will set up basic HTTP authentication in a few minutes
  • Then, we will design a form-based authentication for the web pages, keeping the basic authentication for the RESTful API
  • We will allow the users to sign up via the Twitter OAuth API
  • Then, we will leverage Spring Session to make sure our application can scale using a distributed session mechanism
  • Finally, we will configure Tomcat to use a secured connection through SSL

Basic authentication

The simplest possible authentication mechanism is basic authentication (http://en.wikipedia.org/wiki/Basic_access_authentication). In a nutshell, our pages will not be available without username and password.

Our server will indicate our resources are secured by sending the 401 Not Authorized HTTP status code and generate a WWW-Authenticate header.

To successfully pass the security check, the client must send an Authorization header containing the Basic value followed by a base 64 encoding of the user:password string. A browser window will prompt the user for a username and a password, granting them access to the secured pages if authentication is successful.

Let's add Spring Security to our dependencies:

compile 'org.springframework.boot:spring-boot-starter-security'

Relaunch your application and navigate to any URL in your application. You will be prompted for a username and a password:

Basic authentication

If you fail to authenticate, you will see that a 401 error is thrown. The default username is user. The correct password for authentication will be randomly generated each time the application launches and will be displayed in the server log:

Using default security password: 13212bb6-8583-4080-b790-103408c93115

By default, Spring Security secures every resource except a handful of classic routes such as /css/, /js/, /images/, and **/favicon.ico.

If you wish to configure the default credentials, you can add the following properties to the application.properties file:

security.user.name=admin
security.user.password=secret

Authorized users

Having only one user in our application does not allow fine-grained security. If we wanted more control over the user credentials, we could add the following SecurityConfiguration class in the config package:

package masterSpringMvc.config;

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.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureAuth(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.inMemoryAuthentication()
                .withUser("user").password("user").roles("USER").and()
                .withUser("admin").password("admin").roles("USER", "ADMIN");
    }
}

This snippet will set up an in-memory system containing our application's users as well as their roles. It will override the security name and password previously defined in the application's properties.

The @EnableGlobalMethodSecurity annotation will allow us to annotate our application's method and classes to define their security level.

For example, let's say that only the administrators of our application can access the user API. In this case, we just have to add the @Secured annotation to our resource to allow access only to ADMIN roles:

@RestController
@RequestMapping("/api")
@Secured("ROLE_ADMIN")
public class UserApiController {
  // ... code omitted
}

We can easily test that with httpie by using the -a switch to use basic authentication and the -p=h switch, which will only display the response headers.

Let's try this with a user without the admin profile:

> http GET 'http://localhost:8080/api/users' -a user:user -p=h
HTTP/1.1 403 Forbidden
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/json;charset=UTF-8
Date: Sat, 23 May 2015 17:40:09 GMT
Expires: 0
Pragma: no-cache
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=2D4761C092EDE9A4DB91FA1CAA16C59B; Path=/; HttpOnly
Transfer-Encoding: chunked
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

Now, with the administrator:

> http GET 'http://localhost:8080/api/users' -a admin:admin -p=h
HTTP/1.1 200 OK
Cache-Control: no-cache, no-store, max-age=0, must-revalidate
Content-Type: application/json;charset=UTF-8
Date: Sat, 23 May 2015 17:42:58 GMT
Expires: 0
Pragma: no-cache
Server: Apache-Coyote/1.1
Set-Cookie: JSESSIONID=CE7A9BF903A25A7A8BAD7D4C30E59360; Path=/; HttpOnly
Transfer-Encoding: chunked
X-Content-Type-Options: nosniff
X-Frame-Options: DENY
X-XSS-Protection: 1; mode=block

You will also notice that Spring Security automatically added some common security headers:

  • Cache Control: This prevents the user from caching secured resources
  • X-XSS-Protection: This tells the browser to block what looks like CSS
  • X-Frame-Options: This disallows our site from being embedded in an IFrame
  • X-Content-Type-Options: This prevents browsers from guessing the MIME types of malicious resources used to forge XSS attacks

Note

A comprehensive list of these headers is available at http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#headers.

Authorized URLs

Annotating our controller is very easy but isn't always the most viable option. Sometimes, we just want total control over our authorization.

Remove the @Secured annotation; we will come up with something better.

Let's see what Spring Security will allow us to do by modifying the SecurityConfiguration class:

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Autowired
    public void configureAuth(AuthenticationManagerBuilder auth)
        throws Exception {
        auth.inMemoryAuthentication()
            .withUser("user").password("user").roles("USER").and()
            .withUser("admin").password("admin").roles("USER", "ADMIN");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .httpBasic()
            .and()
            .csrf().disable()
            .authorizeRequests()
            .antMatchers("/login", "/logout").permitAll()
            .antMatchers(HttpMethod.GET, "/api/**").hasRole("USER")
            .antMatchers(HttpMethod.POST, "/api/**").hasRole("ADMIN")
            .antMatchers(HttpMethod.PUT, "/api/**").hasRole("ADMIN")
            .antMatchers(HttpMethod.DELETE, "/api/**").hasRole("ADMIN")
            .anyRequest().authenticated();
    }
}

In the preceding code sample, we configured our application's security policy by using Spring Security's fluent API.

This API allows us to configure Spring Security globally by invoking methods associated with different security concerns and chaining with the and() method.

What we just defined is a basic authentication, without CSRF protection. Requests on /login and /logout will be allowed for all users. GET requests on the API will only be permitted for users with the USER role, whereas POST, PUT, and DELETE requests on the API will only be accessible to users with the ADMIN roles. Finally, every other request will require authentication with any role.

CSRF stands for Cross Site Request Forgery and refers to an attack where a malicious website would display a form on its website and post the form data on yours. If the user of your site is not signed out, the POST request would retain the user cookies and would therefore be authorized.

CSRF protection will generate short-lived tokens that will be posted along with the form data. We will see how to properly enable it in the next section; for now, let's just disable it. See http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#csrf for more details.

Note

To learn more about the authorize request API, have a look at http://docs.spring.io/spring-security/site/docs/current/reference/htmlsingle/#authorize-requests.

Thymeleaf security tags

Sometimes, you will need to display data coming from the authentication layer, for example the user's name and roles, or hide and display part of a web page according to users' authorities. The thymeleaf-extras-springsecurity module will allow us to do so.

Add the following dependency to your build.gradle file:

compile 'org.thymeleaf.extras:thymeleaf-extras-springsecurity3'

With this library, we can add a little block under our navigation bar in layout/default.html to display the logged-in user:

<!DOCTYPE html>
<html xmlns:layout="http://www.ultraq.net.nz/thymeleaf/layout"
      xmlns:th="http://www.thymeleaf.org"
      xmlns:sec="http://www.thymeleaf.org/thymeleaf-extras-springsecurity3">
<head>
  <!-- content trimmed -->
</head>
<body>

<!-- content trimmed -->
<nav>
    <div class="nav-wrapper indigo">
        <ul class="right">
        <!-- content trimmed -->
        </ul>
    </div>
</nav>
<div>
    You are logged as <b sec:authentication="name" /> with roles <span sec:authentication="authorities" />
    -
    <form th:action="@{/logout}" method="post" style="display: inline-block">
        <input type="submit" value="Sign Out" />
    </form>
    <hr/>
</div>

<section layout:fragment="content">
    <p>Page content goes here</p>
</section>

<!-- content trimmed -->
</body>
</html>

Note the new namespace in the HTML declaration and the sec:authentication attributes. It allows access to the properties of the org.springframework.security.core.Authentication object, which represents the user who is currently logged in, as shown in the following screenshot:

Thymeleaf security tags

Don't click on the logout link just yet as it doesn't work with basic authentication. We will get it to work in the next part.

The lib tag also has a handful of other tags, such as the one to check user authorizations:

<div sec:authorize="hasRole('ROLE_ADMIN')">
    You are an administrator
</div>

Note

Please refer to the documentation available at https://github.com/thymeleaf/thymeleaf-extras-springsecurity to learn more about the library.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.16.135.36