'Swagger UI being blocked by Spring Security

I am trying to implement spring security with JWT token, I am trying to achieve authentication with method level authorization

My configuration looks like this SwaggerConfig.java

@Configuration
@PropertySource({"classpath:application.properties"})
@EnableSwagger2
@EnableWebMvc
public class SwaggerConfiguration implements WebMvcConfigurer {

    @Autowired
    private Environment env;

    @Value("${swagger.enable:false}")
    private Boolean isEnabled;

    @Bean
    public Docket swaggerBean() {
        return new Docket(DocumentationType.SWAGGER_2)
                .enable(isEnabled)
                .select()
                .apis(RequestHandlerSelectors.basePackage("com.my.packageapi.v1"))
                .paths(PathSelectors.any())
                .build()
                .apiInfo(getApiInfo())
                .tags(new Tag(env.getProperty("swagger.display.project.name"), env.getProperty("swagger.display.project.description")));
    }

    private ApiInfo getApiInfo() {
        return new ApiInfoBuilder()
                .title(env.getProperty("swagger.display.page.title"))
                .description(env.getProperty("swagger.display.module.description"))
                .version(env.getProperty("swagger.display.version"))
                .build();
    }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("swagger-ui.html").addResourceLocations("classpath:/META-INF/resources/");
        registry.addResourceHandler("/webjars/**").addResourceLocations("classpath:/META-INF/resources/webjars/");
        registry.addResourceHandler("/media/**", "/assets/**", "/static/**", "/images/**", "/css/**", "/js/**")
          .addResourceLocations("classpath:/assets/", "classpath:/static/media/", "classpath:/static/images/",
            "classpath:/static/css/", "classpath:/static/js/", "classpath:js/");
        registry.addResourceHandler("/dist/**").addResourceLocations("/dist/");
        registry.addResourceHandler("/static/**").addResourceLocations("/static/");
        //registry.addResourceHandler(contextPath+"/dist/**").addResourceLocations(contextPath+"/dist/");
        //registry.addResourceHandler(contextPath+"/static/**").addResourceLocations(contextPath+"/static/");
    }

}

WebSecurityConfig.java

@Configuration
@EnableWebSecurity
//@EnableGlobalMethodSecurity(securedEnabled = true)
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class WebSecurityConfig extends WebSecurityConfigurerAdapter implements WebMvcConfigurer {

    @Autowired
    private JwtAuthenticationEntryPoint unauthorizedHandler;

    @Qualifier("userService")
    @Autowired
    private UserDetailsService userDetailsService;

    @Qualifier("ApplicationAuthenticationManager")
    @Autowired
    private AuthenticationManager authenticationManager;

    @Autowired
    private JwtAuthenticationFilter authenticationFilter;

    @Autowired
    private PasswordEncoder encoder;

    @Override
    public AuthenticationManager authenticationManagerBean() {
        return authenticationManager;
    }

    @Autowired
    public void globalUserDetails(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService).passwordEncoder(encoder);
    }

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

        http.cors().and().csrf().disable().
            authorizeRequests()
            .antMatchers(
                "/token/**",
                "/configuration/ui",
                "/swagger-resources/*",
                "/configuration/security",
                "/webjars/*",
                "/swagger-ui*",
                "/favicon*").permitAll()
            .anyRequest().authenticated()
            .and()
            .exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()
            .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        http.addFilterBefore(authenticationFilter, UsernamePasswordAuthenticationFilter.class);
    }

    @Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/v2/api-docs",
            "/configuration/ui",
            "/swagger-resources/*",
            "/configuration/security",
            "/swagger-ui*",
            "/swagger-ui.html/*",
            "/webjars/*");
    }

JWTAthenticationFilter.java

    @Configuration
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    @Qualifier("userService")
    @Autowired
    private UserDetailsService userDetailsService;

    @Autowired
    private TokenProvider jwtTokenUtil;

    @Override
    protected void doFilterInternal(HttpServletRequest req, HttpServletResponse res, FilterChain chain) throws IOException, ServletException {
        String header = req.getHeader(HEADER_STRING);
        String username = null;
        String authToken = null;
        if (header != null && header.startsWith(TOKEN_PREFIX)) {
            authToken = header.replace(TOKEN_PREFIX, "");
            try {
                username = jwtTokenUtil.getUsernameFromToken(authToken);
            } catch (IllegalArgumentException e) {
                logger.error("an error occurred during getting username from token", e);
            } catch (ExpiredJwtException e) {
                logger.warn("the token is expired and not valid anymore", e);
            } catch (SignatureException e) {
                logger.error("Authentication Failed. Username or Password not valid.");
            }
        } else {
            logger.warn("couldn't find bearer string, will ignore the header");
        }
        if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

            UserDetails userDetails = userDetailsService.loadUserByUsername(username);

            if (jwtTokenUtil.validateToken(authToken, userDetails)) {
                UsernamePasswordAuthenticationToken authentication = jwtTokenUtil.getAuthentication(authToken, SecurityContextHolder.getContext().getAuthentication(), userDetails);
                //UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, Arrays.asList(new SimpleGrantedAuthority("ROLE_ADMIN")));
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(req));
                logger.info("authenticated user " + username + ", setting security context");
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }
        System.err.println("Filtering " + req.getContextPath() + "  " + req.getRequestURL());
        chain.doFilter(req, res);
    }
}

JWTAthenticationEntryPoint.java

    @Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint, Serializable {

    @Override
    public void commence(HttpServletRequest request,
                         HttpServletResponse response,
                         AuthenticationException authException) throws IOException {

        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
    }

I have followed it from here

Already tried many of solution, listing few below

Swagger UI empty and gives 403

If you spot any other improvements, please feel free to drop your comments. Every bit of help is appreciated.



Solution 1:[1]

In the ant matchers part add .antMatchers("/v2/api-docs", "/configuration/**", "/swagger*/**", "/webjars/**").permitAll()

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 dcatano