Tag: Spring Security

Setting up Keycloak Server

Keycloak can be downloaded at :-  https://www.keycloak.org/downloads.html

Once it is downloaded, extract the binary distribution and execute the standalone.sh available in the keycloak-9.0.3/bin to run the keycloak server.

References:- https://www.keycloak.org/docs/latest/server_installation/index.html

 

Adding Realm

We need to add a realm first. This can be done by click on Add realm button on top of the server console.

Screen Shot 2020-04-18 at 3.07.35 PM.png

 

Then add the name for the realm. In my case i have added it as “spring-app-demo-realm“.

1.add_realm.png

Now we have successfully added a realm.

 

Adding new users

Now we need to add new users for the newly added realm. For the demonstration purpose i am filling only the mandatory data. I will be creating two user accounts.

  • username: app-user    /   password: test123
  • username: app-admin    /   password: test123

 

Lets create the “app-user” first.

2.add_user.png

Once the user is added, we need to set the password. This can be done as follows.

3.update_password.png

Repeat the above steps again to create the “admin-user” as well.

 

Create Roles

Now we need to create user roles. we will create following two user roles.

  • ROLE_ADMIN
  • ROLE_USER

 

4. add role.png

 

Screen Shot 2020-05-04 at 3.09.23 PM.png

Now we have successfully created the roles.

 

Assign role(s) for the user

Now this is the time to assign the roles for the user accounts. This can be done as follows.

click on Users. ->  select the user account -> Role Mappings

Assigning the user role for the app-admin user

5. assign role for the user.png

Select the available role(s) -> Add Selected

 

Assigning the user role for the app-user

Screen Shot 2020-05-04 at 3.15.21 PM.png

 

Set up client

Now we need to create new client.

6. add client.png

 

Now we need to do more configurations.

7. configure client.png

 

Now we are done with the setup and configuration process.

 

Testing with Postman

8. testing with POSTman.png

 

REST endpoint should in the following format.

http://localhost:8080/auth/realms/<realm-name>/protocol/openid-connect/token

 

 

 

Microservices: How to use Spring Security OAuth2 to Secure Spring REST Api (Resource Server Set up) – Part 3

This is the Part 3 of the series of articles written to share my experience on securing REST Api(s) with Spring Security OAuth2.  The other pars of this article series have been listed below.

Part 1 :  Basics of OAuth2, Roles, Grant types and Microservices security.

Part 2 :  Setting up Authorization server with Spring Security OAuth2 using In-memory token store and client details

Part 3 :  Setting up Resource Server with Spring Security OAuth2.

Part 4 :  Enhancing Authorization server to store client app details and tokens in the database (JDBC client and token store)

Part 5 :  Secure REST Api with Spring Security OAuth2 using JWT token

Part 6 :  Token Revoke and Invalidating

 

Here we will be focusing on how to configure and set up resource server to expose protected resources and allow their access through a valid access token.

In the part 2 of the article, we have looked at how to set up Authorization server and generate token based on valid credentials. In this article, we are going to use the generated access token to access protected resources available.

 

Generating a Project

You need to generate a spring boot project with following dependencies.

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>

 

 

REST Api Resources

In WelcomeController, you can see set of endpoints and those are accessible for different user levels (roles). in order to access each endpoint, we need to have a valid token generated against authorized user credentials.

 

/public endpoint can be accessed by any user (both authenticated and non-authenticated). All other endpoints can be accessed only by authenticated users with allowed user roles.  we can declare that behavior as follows.

according to the above configuration, only the access for the /public will be allowed for the non-authenticated users. all other requests should be authenticated requests.

 

Verifying and Validating the Tokens

You might be thinking of how the resource server internally verify and check the validity of the tokens received through each request. This is accomplished with the /oauth/check_token endpoint exposed in the resource server.  If you check the application.properties of the resource server, you can see that we have declared the endpoint with client app details.

security.oauth2.client.client-id=client
security.oauth2.client.client-secret=password

security.oauth2.resource.token-info-uri=http://localhost:9090/oauth/check_token

 

The resource server will extract the token from the request and check the validity through above endpoint.

 

Accessing the resources with Access Token

Here i have assumed that the authorization server and resource server is already up and running.

since the /public endpoint is permitted to access for all, we should be able to access it without any access token.

Screen Shot 2019-05-25 at 11.03.58 AM.png

 

Now we will try to access the  /admin endpoint without any token. Since our request is not authenticated (does not contain any token), It should not allow us to access the resource. As you can see that we got 401 unauthorized error.

Screen Shot 2019-05-25 at 11.14.59 AM.png

 

Now it is clear that we should have a valid access token to access the /admin resource. lets try to generate an access token based on some user credentials.

username : user

password : password

Screen Shot 2019-05-25 at 11.11.51 AM.png

 

Now we will use the generated access token to access the /admin endpoint.  Here you can see that we have got a different error with different error code.  This is because token will claim only for the ROLE_USER privilege.  In order to access the /admin resource, the token with authority ROLE_ADMIN is required.

Screen Shot 2019-05-25 at 11.14.34 AM.png

 

Lets re-generate the access token with admin credentials.

Screen Shot 2019-05-25 at 11.22.20 AM.png

 

Now we will access the /admin endpoint with access token generated using admin user credentials. Yes! we are done.

Screen Shot 2019-05-25 at 11.26.21 AM.png

 

The Source Code

The Source code of the Resource Server can be found at GitHub. Click here to download it.

 

Microservices: How to use Spring Security OAuth2 to Secure Spring REST Api (Authorization Server with In-memory set up) – Part 2

This is the Part 2 of the series of articles written to share my experience on securing REST Api(s) with Spring Security OAuth2.  The other pars of this article series have been listed below.

Part 1 :  Basics of OAuth2, Roles, Grant types and Microservices security.

Part 2 :  Setting up Authorization server with Spring Security OAuth2 using In-memory token store and client details

Part 3 :  Setting up Resource Server with Spring Security OAuth2.

Part 4 :  Enhancing Authorization server to store client app details and tokens in the database (JDBC client and token store)

Part 5 :  Secure REST Api with Spring Security OAuth2 using JWT token

Part 6 :  Token Revoke and Invalidating

 

Here we will be focusing on how to implement Authorization server to handle client registration and token issuing using in-memory mechanism.

 

Setting up Authorization server

 

You can create a spring boot based project for Authorization server is as follows. Make sure that you have added the Web, OAuth2-Cloud and Spring Security dependencies correctly.

Screen Shot 2019-05-22 at 11.43.10 PM.png

 

once the project is generated, make sure that the following dependencies exist in the pom.xml.

<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
   <groupId>org.springframework.cloud</groupId>
   <artifactId>spring-cloud-starter-oauth2</artifactId>
</dependency>

 

 

Once the project is generated, we can add the WebSecurity Configuration as follows.

 

The Authorization server will authenticate users and issue tokens to access the protected resources.  Since the authorization server does not maintain/expose any resources, we have nothing to secure here. Therefore we haven’t  declared the HTTP or Web Security configurations here. we have created only the authentication-manager.  The users will be authenticated against the in-memory user details store implemented.

 

Adding Authorization Server Configuration 

We have added the Authorization server configuration as follows.

 

clients.inMemory() specifies that we are going to store the services in memory. In a ‘real’ application, we would save it in a database, an LDAP server.As you can see that we have registered one client application in memory.

authorizedGrantTypes – This specifies what are the possible authorization grant types supported by the client application being registered. For this article, we will be using only the password grant type. 

Spring Security OAuth exposes two endpoints for checking tokens (/oauth/check_token and /oauth/token_key). Those endpoints are not exposed by default (have access “denyAll()”).  You can enable those endpoints for authenticated client applications as follows.

oauthServer.checkTokenAccess("isAuthenticated()");

You may add “permitAll()” instead of  “isAuthenticated()

 

Running the Authorization Sever

Now we have done the required configuration for the OAuth2 Authorization server. lets run it and check whether it is working.

mvn spring-boot:run

The server will be up and running on port 9090.

 

Generating Access Token and Refresh Token

The following endpoint can be used to generate the access token and refresh token.

POST  /oauth/token

 

First we need to use the client application credentials to authenticate with Authorization server. Then we can use the user credentials to generate an access token and refresh token for accessing the protected resource.  Please refer the below screenshots.

  • Authenticate using client app credentials

username : client

password :  password

Screen Shot 2019-05-24 at 9.21.31 PM.png

  • Generate access token for the user credentials. 

 

Screen Shot 2019-05-24 at 9.21.42 PM.png

 

You can see that access token and refresh token are generated correctly.

 

Checking and Verifying the Generated Token

You can use the following endpoint to check and verify the generated token.

POST  /oauth/check_token

 

This can be done as follows.

  • Authenticate with client app credentials

username : client

password :  password

Screen Shot 2019-05-24 at 9.30.28 PM.png

 

  • Sending the generated token for retrieving the details. 

Screen Shot 2019-05-24 at 9.32.20 PM.png

You can see that the response contains client app id, scopes, user and authorities/roles.

In the next part, we will look at how to set up resource server to keep protected resources and authorize the access to the protected resources only for the valid/authorized tokens.

 

Source Code

The completed source code of this article can be found at GitHub. Click here to download it.

 

Spring Boot Test and Spring Security: Perform Http Basic Authentication with TestRestTemplate

 

What is HTTP Basic Authentication?

If you want to refresh your knowledge on HTTP Basic Authentication, please click here to refer my article on that.

Here i am going to show you how to execute spring test cases on REST endpoints that are secured with Spring Security and required HTTP Basic Authentication.  Here we are going to use the TestRestTemplate as the REST client for invoking REST endpoints.

 

TestRestTemplate

TestRestTemplate is a convenience alternative to Spring’s RestTemplate that is useful in integration tests. If you use the @SpringBoootTest annotation , with one of the following webEnviroment attribute, you can use fully configured TestRestTemplate in your Test class.

@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
                        OR
@SpringBootTest(webEnvironment = WebEnvironment.DEFINED_PORT)

 

There are different ways that can be used to perform Basic Authentication with TestRestTemplate.

  1.  Authentication headers
  2.  ‘withBasicAuth’ method
  3.  With Authenticated TestRestTemplate object.

Lets look at each of those approaches in detailed as follows.

Continue reading “Spring Boot Test and Spring Security: Perform Http Basic Authentication with TestRestTemplate”

Spring Boot Test: Writing Unit Tests for the Controller Layers with @WebMvcTest

 

Unit Tests and Integration Tests

@SpringBootTest annotation will load the fully ApplicationContext. Therefore it is highly used for writing the integration testing in web server environment. This will not use slicing and scan for all the stereotype annotations (@Component@Service, @Respository and @Controller / @RestController) and loads the full application context. Therefore this is more good at in the context of writing integration testing for the application.

@WebMvcTest annotation will load only the controller layer of the application. This will scan only the @Controller/ @RestController annotation and will not load the fully ApplicationContext. If there is any dependency in the controller layer (has some dependency to other beans from your service layer), you need to provide them manually by mocking those objects.

Therefore @SpringBootTest is widely used for Integration Testing purpose and @WebMvcTest is used for controller layer Unit testing.

Continue reading “Spring Boot Test: Writing Unit Tests for the Controller Layers with @WebMvcTest”

Swagger for documenting your Spring Boot REST Api

 

What Is Swagger?

Swagger is a set of open-source tools built around the OpenAPI Specification that can help you design, build, document and consume REST APIs.

Swagger  is mostly used as an open source project for describing and documenting RESTful APIs.  Swagger-UI an another tool which provides the capability of displaying the REST Api documentation in the browser.  Besides rendering documentation, Swagger UI allows other API developers or consumers to interact with the API’s resources without having any of the implementation logic in place.

The more details can be found through following documentations.

https://swagger.io/docs/ 

http://springfox.github.io/springfox/docs/current/

 

Springfox for Swagger

The Swagger 2 specification, which is known as OpenAPI specification has several implementations. Currently, Springfox that has replaced Swagger-SpringMVC (Swagger 1.2 and older) is popular for Spring Boot applications.

Continue reading “Swagger for documenting your Spring Boot REST Api”

Enable Cross Origin Resource Sharing (CORS) for Spring REST Api

 

 

What is CORS (Cross Origin Resource Sharing)?

Cross Origin Resource Sharing is something that is declared by the w3c on communication between different domains. By CORS, communications between the same domain will be allowed to users and the communications that are cross-originated will be restricted to a few techniques. We can see this when we are talking to APIs mostly. The REST call may give us an error. This is because the server and the client sides are on different domains and the communication between them are restricted by CORS rules.

If you want to learn more,please do a google search. you can find a lot of resources related to CORS and their importance. 

The Spring has given a nice explanation and that can accessed with following URL.

https://spring.io/understanding/CORS

 

Importance of CORS

The importance of the CORS implementation comes with the security aspects. It blocks the calls made by unknown domains and keeps the paths open only to the known domains. So the security is ensured despite the attacking requests.

 

Continue reading “Enable Cross Origin Resource Sharing (CORS) for Spring REST Api”

Spring Security : Authentication interface

Authentication interface is one of the most core interface available in the Spring Security framework. There are different uses (implementations) of Authentication interface and those can be described as follows.

 

1. Submitting the Authentication request for the AuthenticationManager

authenticate( ) method of the AuthenticationManager, requires an Authentication object as its method parameter. This will be the authentication request submitted for the AuthenticationManager. There are several implementations available to represent this Authentication request and the most popular implementation is UsernamePasswordAuthenticationToken.

Here is the AuthenticationManager interface. 

public interface AuthenticationManager 
{
   Authentication authenticate(Authentication authentication) throws AuthenticationException;
}

 

2. Returning the Authentication response from the AuthenticationManager

Again you can notice that the return type of the authenticate() method of the AuthenticationManager is, in the form of Authentication interface. Therefore the authenticated response will also be represented by Authentication interface.

 

3. Storing the Authenticated Principal in the SecurityContext.

Authenticated Response will be stored in the SecurityContext using the Authentication interface.

 SecurityContextHolder.getContext().setAuthentication(authentication);

 

Here is the diagram of Authentication request and response from AuthenticationManager

 

Spring Security

The Authentication object created as the authentication request contains only the username and password. it does not contain the authorities and authenticated attribute is set as FALSE.

but in the Authenticated response, authenticated attribute is set as TRUE. In addition, it contains the list of authorities granted/available for the authenticated principal.

Securing Spring REST Api with Spring Security and JWT (Json Web Token)

In this article, i am going to demonstrate how to user JWT (Json Web Token) Authentication with Spring boot and Spring Security.  In here, i am not going to discuss the basic theory and details about the JWT and you can search google and find a lot of resources related to that.

GitHub URL :-  https://github.com/chathurangat/spring-rest-jwt-auth-example 

I will update a screenshot of my project structure to get an idea of project structure and class/files locations. Don’t worry! This is just to get an idea. We will be doing everything one by one as we are proceeding.

Screen Shot 2017-07-17 at 3.07.00 PM

Before starting with the development, i will briefly give you an idea about the classes that we are going to develop in this article.
First step is to create spring boot web project. This can be easily created with Spring Initializer (https://start.spring.io/). Remember to add web and spring security dependencies for your app.  In addition to that, it is important to add JWT dependency.

Required dependencies in pom.xml

<?xml version="1.0" encoding="UTF-8"?>
	<dependencies>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-security</artifactId>
		</dependency>

		<dependency>
			<groupId>org.springframework.boot</groupId>
			<artifactId>spring-boot-starter-web</artifactId>
		</dependency>

        <dependency>
            <groupId>io.jsonwebtoken</groupId>
            <artifactId>jjwt</artifactId>
            <version>0.6.0</version>
        </dependency>

	</dependencies>

Then create a JwtService class as below. The JwtService class will be used for following two purposes.

  • Generate JWT token based on username upon successful user login.
  • Validate /Authenticate JWT token (user send along with every request)  and extract user information from the token.

JwtService.java 


import com.chathuranga.rest.jwt.auth.SecretKeyProvider;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.URISyntaxException;
import java.time.LocalDateTime;
import java.util.Date;

import static java.time.ZoneOffset.UTC;

@Component
public class JwtService {

    private static final String ISSUER = "com.chathuranga.examples";

    @Autowired
    private SecretKeyProvider secretKeyProvider;

    public String generateToken(String username) throws IOException, URISyntaxException {
        byte[] secretKey = secretKeyProvider.getKey();
        Date expiration = Date.from(LocalDateTime.now(UTC).plusHours(2).toInstant(UTC));
        return Jwts.builder()
                .setSubject(username)
                .setExpiration(expiration)
                .setIssuer(ISSUER)
                .signWith(SignatureAlgorithm.HS512, secretKey)
                .compact();
    }

    public String verifyToken(String token) throws IOException, URISyntaxException {
        byte[] secretKey = secretKeyProvider.getKey();
        Jws<Claims> claims = Jwts.parser().setSigningKey(secretKey).parseClaimsJws(token);
        //returning authenticated/verified username
        return claims.getBody().getSubject();
    }
}

Now we need to create a LoginController for authenticating users with their credentials (username and password) and issue JWT token (using JwtService) upon successful authentication

LoginController.java


import com.chathuranga.rest.jwt.auth.exception.FailedToLoginException;
import com.chathuranga.rest.jwt.auth.model.AuthenticationResponse;
import com.chathuranga.rest.jwt.auth.model.UserCredentials;
import com.chathuranga.rest.jwt.auth.service.UserAuthenticationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.*;

@RestController
public class LoginController {

    @Autowired
    private UserAuthenticationService authenticationService;

    @ResponseStatus(HttpStatus.OK)
    @RequestMapping(value = "/login", method = RequestMethod.POST)
    public AuthenticationResponse userLogin(@RequestBody UserCredentials userCredentials) throws FailedToLoginException {

        if (userCredentials == null || (userCredentials.getUsername() == null || userCredentials.getPassword() == null)) {
            throw new FailedToLoginException("Missing login credentials ");
        }

        String token = authenticationService.authenticateUser(userCredentials.getUsername(), userCredentials.getPassword());

        if (token != null) {
            AuthenticationResponse authenticationResponse = new AuthenticationResponse();
            authenticationResponse.setUsername(userCredentials.getUsername());
            authenticationResponse.setToken(token);
            return authenticationResponse;
        }
        throw new FailedToLoginException(String.format(" unable to authenticate user [%s] ", userCredentials.getUsername()));
    }
}

Here is the Implementation of the UserAuthenticationService class. For the demonstration purpose i have hard coded two user credentials. But in production environment, you need to implement JPA based user repository or some other mechanism like LDAP or OpenId.

UserAuthenticationService.java


import com.chathuranga.rest.jwt.auth.exception.FailedToLoginException;
import com.chathuranga.rest.jwt.auth.exception.JwtAuthenticationException;
import com.chathuranga.rest.jwt.auth.model.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.net.URISyntaxException;
import java.util.List;

@Component
public class UserAuthenticationService {

    @Autowired
    private JwtService jwtService;

    @Autowired
    private UserService userService;

    public String authenticateUser(String username, String password) throws FailedToLoginException {
        boolean isAuthenticated = false;
        if (username.equals("chathuranga") && password.equals("test123")) {
            isAuthenticated = true;
        } else if (username.equals("bob") && password.equals("test123")) {
            isAuthenticated = true;
        }

        if (isAuthenticated) {
            try {
                return jwtService.generateToken(username);
            } catch (URISyntaxException | IOException e) {
                throw new FailedToLoginException(e.getMessage());
            }
        }
        throw new FailedToLoginException(String.format("unable to authenticate user [%s]", username));
    }

    public User authenticateToken(String jwtToken) throws JwtAuthenticationException {

        try {
            String username = jwtService.verifyToken(jwtToken);
            List<String> userRoles = userService.getUserRoles(username);

            User user = new User();
            user.setUsername(username);
            user.setUserRoles(userRoles);
            return user;
        } catch (IOException | URISyntaxException e) {
            throw new JwtAuthenticationException(e.getMessage(), e);
        }
    }
}

One more thing! I forgot to show you the implementation of AuthenticationResponse class.
This is just a POJO class implemented to return the successful authentication response back to the client. Here is the implementation. You will notice that we are returning username and JWT token back to the client.

AuthenticationResponse.java


package com.chathuranga.rest.jwt.auth.model;

public class AuthenticationResponse {

    private String username;
    private String token;

    public String getToken() {
        return token;
    }

    public void setToken(String token) {
        this.token = token;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }
}

Once this LoginController is fully developed, we should be able to authenticate users with their credentials. We have hardcoded few user credentials. I am going to test the user authentication with those credentials using Postman tool.

Username: chathuranga
Password: test123

Username: bob
Password: test123

Here is my Postman request.

Screen Shot 2017-07-17 at 4.33.39 PM

Here is the response retrieved. You can see that i am getting the username and JWT token as the response.

Now we have the JWT token. So we can use this token to show our authenticity.

Accessing Secured Api

Please refer the below secured controller. It has two methods to support for two endpoint URLs.

1. /api/admin/hello – this can be accessed only by users with ROLE_ADMIN
2. /api/user/hello – this can be accessed only by users with ROLE_USER


package com.chathuranga.rest.jwt.controller;

import org.springframework.http.HttpMethod;
import org.springframework.security.access.annotation.Secured;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;

@RestController
@RequestMapping(value = "/api")
public class WelcomeController {

    @Secured("ROLE_ADMIN")
    @RequestMapping(path = "/admin/hello", method = RequestMethod.GET)
    public String helloAdminController() {
        String loggedUserName = SecurityContextHolder.getContext().getAuthentication().getName();

        return "Hello Admin " + loggedUserName;
    }

    @Secured("ROLE_USER")
    @RequestMapping(path = "/user/hello", method = RequestMethod.GET)
    public String helloUserController() {

        String loggedUserName = SecurityContextHolder.getContext().getAuthentication().getName();

        return "Hello User " + loggedUserName;
    }
}

Please refer the following Postman screenshot.

Screen Shot 2017-07-17 at 3.03.31 PM

Spring Security Related Configurations and Implementation Classes

SecurityConfig.java


import org.springframework.beans.factory.annotation.Autowired;
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.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;

@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, jsr250Enabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private JwtAuthFilter authFilter;

    @Autowired
    private JwtAuthenticationProvider authenticationProvider;

    @Autowired
    private JwtAuthenticationEntryPoint authenticationEntryPoint;

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(authenticationProvider);
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.csrf().ignoringAntMatchers("/login");

        http.authorizeRequests()
                .antMatchers("/login")
                .permitAll()
                .antMatchers("/api/**")
                .authenticated()
                .and()
                .addFilterBefore(authFilter, UsernamePasswordAuthenticationFilter.class)
                .exceptionHandling()
                .authenticationEntryPoint(authenticationEntryPoint);
    }
}

  • Here we have used a custom authentication provider called JwtAuthenticationProvider. It will be used to authenticate users , based on JWT token.  
  • We have disabled the CSRF token validation for URL  /login.  
  • Any request coming to /login will be permitted and any request coming to URL /api/** should be authenticated.
  • We have created a custom Filter (JwtAuthFilter) and it will be applied before executing UsernamePasswordAuthenticationFilter

Any authentication related exception will be handled using the custom authentication entry point provided.(That is JwtAuthenticationEntryPoint)

JwtAuthFilter.java

This filter will be used to capture the JWT token sent by the users through Authorization header. This will find the JWT token in the request header and set it in the Authentication object before executing the UsernamePasswordAuthenticationFilter provided by the Spring security.

(The filter creates an instance of  JwtAuthToken class with token retrieved and set it as  the current Authentication object for the request)

import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

import javax.servlet.*;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

@Component
public class JwtAuthFilter implements Filter
{

    @Override
    public void doFilter(ServletRequest request, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException
    {
        HttpServletRequest servletRequest = (HttpServletRequest) request;
        String authorization = servletRequest.getHeader("Authorization");

        if (authorization != null)
        {
            JwtAuthToken token = new JwtAuthToken(authorization.replaceAll("Bearer ", ""));
            SecurityContextHolder.getContext().setAuthentication(token);
        }
        filterChain.doFilter(servletRequest, servletResponse);
    }

    @Override
    public void destroy()
    {

    }

    @Override
    public void init(FilterConfig filterConfig) throws ServletException
    {

    }
}

 

JwtAuthenticationProvider.java

import com.chathuranga.rest.jwt.auth.model.User;
import com.chathuranga.rest.jwt.auth.service.UserAuthenticationService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.stereotype.Component;

@Component
public class JwtAuthenticationProvider implements AuthenticationProvider
{

    @Autowired
    private UserAuthenticationService authenticationService;

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException
    {
      User user =  authenticationService.authenticateToken((String) authentication.getCredentials());
      return new JwtAuthenticatedUserToken(user.getUsername(),user.getUserRoles());
    }

    /*
     Returns true if this AuthenticationProvider supports the indicated Authentication object.
     */
    @Override
    public boolean supports(Class<?> aClass)
    {
        return JwtAuthToken.class.equals(aClass);
    }
}

The JwtAuthenticationProvider receives the Authentication instance set on the SecurityContext, which in our case is the JwtAuthToken we set using the JwtAuthFilter. This token is then verified using the JwtService. If the token is valid, we return a JwtAuthenticatedUserToken (username and ACL – Access Control List) or throw an AuthenticationException if it is invalid. Any authentication related exception (an instance of AuthenticationException) will be handled by JwtAuthenticationEntrypoint.

JwtAuthenticationEntryPoint.java

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.http.MediaType;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;

import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.Collections;

import static javax.servlet.http.HttpServletResponse.SC_FORBIDDEN;

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint
{
    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, AuthenticationException e)
            throws IOException, ServletException {
        httpServletResponse.setStatus(SC_FORBIDDEN);
        httpServletResponse.setContentType(MediaType.APPLICATION_JSON_VALUE);

        String message;
        if(e.getCause() != null) {
            message = e.getCause().getMessage();
        } else {
            message = e.getMessage();
        }
        byte[] body = new ObjectMapper()
                .writeValueAsBytes(Collections.singletonMap("error", message));
        httpServletResponse.getOutputStream().write(body);
    }
}