Form & Basic Security :
Suppose you have a spring boot application and you want to add security features to it, the easiest way would be to add Spring Security dependency to Spring boot project. This dependency enables both Form based Authentication and Basic Authentication.
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> </dependency>
In Form based Authentication, you will be using a web browser and on the first call of the URL an Form will pop-up and it will ask for the username and password. On 2nd call onwards it won’t ask for anything and you will be able to access the URL. So basically here, an sessionId is stored at the server side and a browser cookie is maintained at the client side. And this helps in recognizing the user.
In Basic Authentication you will be using a web client like Postman and you will be sending the credentials as part of Basic Authorization Header and it goes to server in an encrypted format (Base64 Encoded).
So here also there is a cookie maintained which is passed as the jsessionid along with every request after the first call:
So JSESSIONID is the default authentication token created by Spring Security framework. If you want to optimize it for your production ready application you can use JWT tokens, OAuth tokens, etc.
So, if you are using Form based or Basic authentication the credentials will be as below:
Username: user
Password: [This you can look for in the console logs]
In the logs you can see something like below:
Using generated security password: 346ce2c6-ba46-4272-ab4b-e936076c48cd
After entering the above credentials you will be able to access the URLs now.
There is another way to have the credentials, you can add those in the application.properties file like below. No need to look for the password in the console log:
spring.security.user.name=user spring.security.user.password=password
Just bounce (restart) the application.
Now you will have to give above credentials to access the URLs.
JWT Security:
Above we saw Form & Basic Authentication in Spring application .
Below are the drawbacks of Basic Authentication:
- No expiration time.
- Possesses only username/password and no other user information (like Authorization, Signature, etc.)
So, the need arises to make a Custom Token System which all parties should understand. But due to its Custom Structure it may have some security flaws.
Then we came up with a common Standard Token System which we call JWT. It is basically a mixture of Standard and Custom User information.
How an JWT Token look like ?
It has basically 3 parts :
Header
Payload
Signature.
It look something like below, in the below pic the left side column is an JWT token :
So how an Authentication scenario would be?
Below is the sequence of incidents:
For the first time when the user tries to access the URL he/she have to enter the username and password. The request would go to the server and it will generate JWT and it would be send back to the user. For 2nd time onwards user has to pass JWT as part of Authorization Header.
JWT token will be having an expiration period. When the expiration period would be coming near you can send an Refresh Token request- so basically you are asking for a new token.
Lets see in action the above steps:
1. So for authenticating we have to do a POST call to below URL: (suppose 8080 is the port where your application is running)
http://localhost:8080/authenticate
with below parameter:
{ "username":"heapsteep", "password":"heapsteep" }
I will tell you later where we had configured the above credentials. Anyway if you are too curious to know, here is the place.
You will get the JWT token as response, as shown in below pic:
2. Going forward you have to pass this token in all subsequent request.
Suppose you have to do a GET call to below URL:
http://localhost:8080/2
Add an Header and give it the name- Authorization and add value as below:
Bearer <Token>
Keep a space between Bearer and Token.
P.S.: Suppose there are 3 endpoints for your application as below:
http://localhost:8080
http://localhost:8080/1
http://localhost:8080/2
For accessing the first one you won’t need any JWT token, but accessing the 2nd and 3rd URL an JWT token would be required. Seems like for the root you can’t restrict it.
Source code of this demo application can be found here: https://github.com/heapsteep/jwt-demo.git
Lets drill down the project and see what is what. This would be very exiting !…
In your existing spring security application you can add below dependency manually, its not available in Spring Initializr:
<dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency>
We had separated out the JWT implementation to a separate package named- jwt. There are around 10 files.
All the REST handlers are kept in package name- controller.
application.properties file contains below info.
jwt.signing.key.secret=mySecret jwt.get.token.uri=/authenticate jwt.refresh.token.uri=/refresh jwt.http.request.header=Authorization jwt.token.expiration.in.seconds=604800
604800 seconds = 168 hrs.
In test package we have this test class. This will help you in generating the encoded password.
public class BCryptEncoderTest { public static void main(String[] args) { BCryptPasswordEncoder encoder=new BCryptPasswordEncoder(); System.out.println(encoder.encode("heapsteep")); } }
If you run this class it will give you the password like below:
$2a$10$VrWrjTWrDsYgUtkV4m.VZeTR.xka6qsOVsHM47STjtgESWkVuIx1m
P.S. For the same string you may get different encoded string every time you run the encoder.
Copy and paste the above generated password in to the below file- JwtInMemoryUserDetailsService. This file is the static in-memory credential file:
@Service public class JwtInMemoryUserDetailsService implements UserDetailsService { static List<JwtUserDetails> inMemoryUserList = new ArrayList<>(); static { inMemoryUserList.add(new JwtUserDetails(1L, "heapsteep", "$2a$10$VrWrjTWrDsYgUtkV4m.VZeTR.xka6qsOVsHM47STjtgESWkVuIx1m", "ROLE_USER_2")); }
So, for your microservice, if you want to incorporate JWT in it, you have to copy paste the jwt folder from this sample application to your microservice and do the above changes as well.
Yes, you have to do this for all microservices.