Building Microservice with Spring Boot — Part 03

Secure API Gateway | Authentication and Authorization | JWT

Microservices with Spring Boot | Secure API Gateway | Authentication & Authorization | JWT

Configure Authentication and Authorization Layer to Secure API endpoints.

Security is one of the biggest concerns in software application development. To secure API inside the microservices application, We can use many methods. Here I’m going to secure the API gateway which we built previous post, by authenticate and authorize requests from API consumers. It’ll ensure the overall security inside the microservices application.

To build the auth layer, I’m going to create another service named as ‘auth-service’. Basically, ‘auth-service’ is controlling the authentication of users by generating JWT tokens for successful authentication and ‘API Gateway’ will validate authentication tokens for each and every request going through.

Let’s create and register another spring boot application with @EnableEurekaClient and register it into the services registry (Please refer Part 1 for creating a Eureka Client App).

Facilitate auth-service to produce JWT tokens for valid user credentials.

Adding dependencies for Spring security, JWT and Mongo DB to gradle

compile group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.0'
compile 'org.springframework.boot:spring-boot-starter-data-mongodb'
implementation('org.springframework.boot:spring-boot-starter-security')

Here I’ve used MongoDB to manage user store.

Database Mapping and repository to retrieve user.

This app will use simple user and user role mapping for demo purpose. We can add more capabilities like privileges to role management if needed.

Configure spring security inside the project.

JWT config is the configuration class which is going to use for configuration for JWT generation in the application.

What’s inside?

  1. Uri — URL which is going to use as POST method to authenticate using spring security
  2. header — Header key name which is going to use for sending auth token
  3. prefix — Unique prefix which has to be bind with auth token when requesting. Without knowing the correct prefix and attacker who breached in to the system cannot access without knowing the correct prefix even though he was somehow able to create a token.
  4. expiration — Expiration time of generated tokens in seconds. (Here token valid for 24 Hours)
  5. secret — secret to use when generating a token.

JwtUsernameAndPasswordAuthenticationFilter is use to filter auth credentials and issue tokens upon successful login.

JwtUsernameAndPasswordAuthenticationFilter.java

What’s happening here?

this.setRequiresAuthenticationRequestMatcher(new AntPathRequestMatcher(jwtConfig.getUri(), "POST"));

Above code will create a POST method with the URI which is stated in the configuration and listens for requests which are coming into the POST method.

What’s happening in the successfulAuthentication method ?

String token will be generated along with authorities, expiration and secret key. Then sends a response after binding generated token in headers.

Which will take care of capturing and redirecting user request to filters ? It’s done by SecurityConfig which enables web security.

Before creating securiy config we’ve to create beans for BCryptPasswordEncoder and JwtConfig. BcrypPasswordEncoder will be used to encode passwords inside the application. So to do that just add following inside main application class.

@Bean
public BCryptPasswordEncoder bCryptPasswordEncoder(){
return new BCryptPasswordEncoder();
}
@Bean
public JwtConfig jwtConfig() {
return new JwtConfig();
}

After that we’ve to have a method to retrieve user from DB and validate authentication details against users details which saved in DB. To do that, we can use implementation of org.springframework.security.core.userdetails.UserDetailsService as below.

What’s happening inside UserDetailsServiceImpl ?

Basically, UserdetailsServiceImpl overrides ‘ loadUserByUsername’ method from org.springframework.security.core.userdetails.UserDetailsService, So we’ve just have to implement a method to search user from db and return a object in org.springframework.security.core.userdetails.User binding all username, encoded password and user roles.

!!! Important, Keep in mind to add user roles format like ROLE_ADMIN, ROLE_NEWS since Spring security need ROLE_…. prefix in role names.

Implementing main security configuration.

Here I’m going to manually handle the sessions using JWT tokens, Hence spring security doesn’t need to handle user sessions. So that’s why we’re using SessionCreationPolicy.STATELESS.

How we can control when sessions get created in spring security?

always — a session will always be created if one doesn’t already exist
ifRequired — a session will be created only if required (default)
never — the framework will never create a session itself but it will use one if already exists
stateless — no session will be created or used by Spring Security

Additionally, we’re going to permit a single URL to access without authentication by,

.antMatchers(HttpMethod.POST, jwtConfig.getUri()).permitAll()

Here it’s the URL which is to be used with the login function. So it doesn’t need to be authenticated.

Ok, Since the ‘auth-service’ is ready to produce auth token upon user authentication and now we’ve to configure API gateway to route authentication request to ‘auth-service’ and validate each and every request going through the API gateway.

Configure API Gateway

Gradle Dependencies

implementation('org.springframework.boot:spring-boot-starter-security')
// https://mvnrepository.com/artifact/io.jsonwebtoken/jjwt
compile group: 'io.jsonwebtoken', name: 'jjwt', version: '0.9.0'

JWTConfig.

Keep in mind to add same values for JWTConfig which used in auth-service, Since Jwtconfig include the secret and expiration time of JWT tokens. If these values not tally, API gateway coudn’t validate request.

JwtTokenAuthenticationFilter

The main purpose of ‘JwtTokenAuthenticationFilter’ is to filter request header in order to capture jwt data and validate authentication. So if the request is coming with a valid token, then the request will be approved and send to the API endpoint, if it not then filter will respond with a 403 (Forbidden) response.

Security Config with @EnableWebSecurity

Manage Authorization using user roles in Spring Boot.

As you can see in above gist, I’ve added two antMatchers like ,

.antMatchers("/user/**").hasRole("ADMIN")
.antMatchers("/news/**").hasRole("NEWS")

Here it validates the request token has bind the correct role like ‘ADMIN’ or ‘NEWS’ to grant access to both URLs. Basically, the valid token will authorize any user request with correct role to access the API endpoint.

Fine, Now our application has configured to produce access tokens to authenticate and authorize API gateway requests. Let’s test the infrastructure.

Start and register all microservices in to the Service Registry.

Spring Eureka Service Registry — Building Microservice with Sprign Boot — Part 03

Registered users inside auth-service.

Here I’ve wrote a POST method to register users and gave permitAll to user in order to request without auth tokens.
Registered users — Building microservice with spring boot

Generate JWT Token using ‘newsuser’.

Authenticate for newsuser

Using generated token and call /news/** API.

Search News Web Service API

Use same token to access /user/** API.

403 Forbidden

Done, all works perfectly.

Additional Security Improvements

Here I’ve configured API gateway to secure the API, Since it’s the main entry point to the microservices platform. Though API Gateway is secured, API endpoints can be a victim of attacks. My opinion is to use Mutual SSL to establish more secured connections between microservices and API gateway. So if we can configure Mutual SSL between API gateway and each service, It’ll provide highlevel security inside the microservices project.

Cheers !!!!!!

Building Microservices with Spring Boot — Part 04

Zipkin | Circuit Breaker | Swagger2