FC
FACADE
CODE
Lesson 15 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

PostAuthorize

@PostAuthorize does the same job as @PreAuthorize, but does it after the execution of the annotated service method. In doing so we get access to the return value of the method which can be used to make authorization decision inside @PostAuthorize. But there is a caveat that any operation which changes the state of the application must be avoided.

Secure view profile service

Though we have secured the below service method with VIEW_PROFILE permission, any authenticated user can view other user's profile because this permission is assigned to all the Roles.


@PreAuthorize(Authority.VIEW_PROFILE)
public AppUser get(Long userId) {
    return appUserRepository.findById(userId)
            .orElse(null);
}

In order to secure this service method we need to ensure that the authenticated user and the requested user profile are same.

We can get the authenticated user's username from Authentication object in SecurityContextHolder. And Spring Security provides an in-built expression to access this Authentication object using SpEL expression authentication before the execution of the method.

But unless we find the requested user profile from the repository and confirm that it is same as the authenticated user we can't authorize. @PostAuthorize allows us to access this requested user profile from the return value using SpEL expression returnObject after the execution of the method.


@PreAuthorize(Authority.VIEW_PROFILE)
@PostAuthorize("returnObject.username == authentication.name")
public AppUser get(Long userId) {
    return appUserRepository.findById(userId)
            .orElse(null);
}

Here returnObject represents the return value of the method which is AppUser object. We are checking username of the requested AppUser object is equal to the name of the Authentication object after the execution of the method.

Above service returns the AppUser object only for authorized requests post execution, but throws 403 Forbidden error for unauthorized requests. Though the service executes all the time, it doesn't change the state of the application.

Test view profile

Now restart the application, send a GET request to ViewProfile API using Gru to view his own profile and we will be authorized to view his profile.

Authorized request to view Gru profile with Gru's credential
Authorized request to view Gru profile with Gru's credential

But we will get 403 Forbidden error if we send the same request to view Gru's user profile using any other user credentials.

Unauthorized request to view Gru profile with Bob's credential
Unauthorized request to view Gru profile with Bob's credential