FC
FACADE
CODE
Lesson 8 of 28
FC
FACADE
CODE

Learn Spring Security

Contents

01. Bootstrap The Application
1. Introduction
2. Install Spring Security
3. Enable Basic Auth
4. Authentication with AppUser
5. Password Encoder
02. Web Layer Security - RBAC
6. Permit Public APIs
7. Role Based Authorization
8. Disable CSRF
9. Current Authenticated User
03. Web Layer Security - PBAC
10. Permission Based Authorization
11. Define Permissions
12. Assign Permissions
13. Remove Role Based Access
04. Service Layer Security
14. PreAuthorize
15. PostAuthorize
16. Authorize Using Spring Beans
05. Domain Object Instance Security
17. Domain Object Instance Security
18. PermissionEvaluator Interface
19. PermissionEvaluator Strategy
20. DB Backed UserDetailsService
06. Token Based Authentication
21. Basic Authentication Revisited
22. Generate Token
23. Persist Token
24. Verify Token
25. Invalidate Token
07. Token Based Authentication and Authorization
26. JSON Web Token
27. Generate JWT
28. Verify JWT

Disable CSRF

After applying role-based authorization in the last chapter, we can access ListStudents and ListInstructors API only with users having ADMIN role. Similarly we can access CreateCourse API only with users having INSTRUCTOR role. Let's create a new course by sending a POST request to CreateCourse API with Gru who has INSTRUCTOR role.

403 Forbidden error returned for Gru (Instructor) while accessing Create Course API
403 Forbidden error returned for Gru (Instructor) while accessing Create Course API

Surprisingly we have got 403 Forbidden error even though Gru has the INSTRUCTOR role. Let's update the application.properties in order to enable the DEBUG log for Spring Security and see what is happening behind the scene.


logging.level.org.springframework.security=DEBUG    

Restart the application and send the same request again. You can see an error stating "Invalid CSRF token found for http://localhost:8080/api/v1/courses" in the log something like below:


o.s.security.web.FilterChainProxy        : Securing POST /api/v1/courses
w.c.HttpSessionSecurityContextRepository : Retrieved SecurityContextImpl [...]
s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to SecurityContextImpl [...]
o.s.security.web.csrf.CsrfFilter         : Invalid CSRF token found for http://localhost:8080/api/v1/courses
o.s.s.w.access.AccessDeniedHandlerImpl   : Responding with 403 status code
s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request
o.s.security.web.FilterChainProxy        : Securing POST /error
w.c.HttpSessionSecurityContextRepository : Retrieved SecurityContextImpl [...]
s.s.w.c.SecurityContextPersistenceFilter : Set SecurityContextHolder to SecurityContextImpl [...]
o.s.s.w.a.i.FilterSecurityInterceptor    : Authorized filter invocation [POST /error] with attributes [authenticated]
o.s.security.web.FilterChainProxy        : Secured POST /error
s.s.w.c.SecurityContextPersistenceFilter : Cleared SecurityContextHolder to complete request   

What is CSRF and CSRF Token?

Cross-Site Request Forgery (CSRF) is an attack that forces authenticated users to submit a request to a Web application in which they are currently authenticated.

Assume you are browsing through an evil website, while still logged in with your Banks' website. The evil website can force you to click an image, link or button, which then can send an unsolicited fund transfer request to your Bank's website from the evil website. Though the evil website can not see your cookies, the cookies associated with your Bank's website are still sent along with your request. And your Bank's website in no way can differentiate this malicious request, it executes the requested fund transfer.

CSRF attacks can be prevented using CSRF token, a secure random token unique per user session known only to the application and it's user interface.

When to use CSRF protection

CSRF protection is enabled by default in Spring Security for those HttpMethod which potentially can change the state of the application: POST, PUT, DELETE and/or PATCH.

Spring Security recommends to use CSRF protection for any request that could be processed by a browser by normal users. If you are only creating a service that is used by non-browser clients, you will likely want to disable CSRF protection.

Disable CSRF protection

For the purpose of our course, let's disable CSRF by chaining csrf().disable() method call with HttpSecurity like below:


@Configuration
public class ApiSecurityConfig {
    @Bean
    public SecurityFilterChain apiFilterChain(HttpSecurity http) throws Exception {
        http
            .csrf().disable()
            .authorizeRequests(auth -> auth
                .antMatchers(GET, PUBLIC_API_LIST).permitAll()
                .antMatchers(API_LIST_STUDENTS, API_LIST_INSTRUCTORS).hasRole(ADMIN.name())
                .antMatchers(POST, API_CREATE_COURSES).hasRole(INSTRUCTOR.name())
                .anyRequest().authenticated()
            )
            .httpBasic();
        return http.build();
    }
}

If we send the CreateCourse API request again with Gru after restarting the application, we can see the course got created with 201 Created status. Whereas it throws 403 Forbidden error for the users who does not have the INSTRUCTOR role.

New course created for Gru after disabling CSRF
New course created for Gru after disabling CSRF