How to secure swagger UI with basic Authentication when using JWT Authentication

138 Views Asked by At

Dears

I am using spring fox with Spring Security. I have a custom JwrRequestFilter that extracts the jwt from the request and authenticates the user.

My issue is, that I need a basic popup authentication alert to appear when user hits /swagger-ui.html

here is my Security Config .configure() method:

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
            .cors()
            .and()
            .sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and()
            .csrf().disable()
            .formLogin().disable()
            .httpBasic().disable()
            .exceptionHandling()
            .authenticationEntryPoint(new JwtAuthenticationEntryPoint())
            .and()
            .authorizeRequests()
            .antMatchers("/",
                    "/error",
                    "/favicon.ico",
                    "/**/*.png",
                    "/**/*.gif",
                    "/**/*.svg",
                    "/**/*.jpg",
                    "/**/*.html",
                    "/**/*.css",
                    "/**/*.js",
                    "/v2/api-docs",
                    "/configuration/ui",
                    "/swagger-resources/**",
                    "/configuration/security",
                    "/swagger-ui.html",
                    "/review/notify",
                    "/demo/**",
                    "/communication/**",
                    "/info/**",
                    "/images/***",
                    "/images/**/**",
                    "/webjars/**",
                    "/scrapper/**",
                    "/", "/actuator/**").permitAll()
            .antMatchers("/auth/**",
                    "/oauth2/**", "/internal/**")
            .permitAll()
            .anyRequest()
            .authenticated()
            .and()
            .oauth2Login()
            .authorizationEndpoint()
            .baseUri("/oauth2/authorize")
            .authorizationRequestRepository(cookieAuthorizationRequestRepository())
            .and()
            .redirectionEndpoint()
            .baseUri("/oauth2/callback/*")
            .and()
            .userInfoEndpoint()
            .userService(customOAuth2UserService)
            .and()
            .successHandler(oAuth2AuthenticationSuccessHandler)
            .failureHandler(oAuth2AuthenticationFailureHandler);

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

And the jwtRequestFilter:

 @Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
        throws ServletException, IOException {
    final String requestTokenHeader = request.getHeader(Constants.AUTHORIZATION_HEADER);
    String username = null;
    String jwtToken = null;
    // JWT Token is in the form "Bearer token". Remove Bearer word and get
    // only the Token
    if (requestTokenHeader != null && requestTokenHeader.startsWith(Constants.TOKEN_PREFIX)) {
        jwtToken = requestTokenHeader.substring(7);
        try {
            username = jwtTokenUtil.getEmailFromToken(jwtToken);
        } catch (IllegalArgumentException e) {
            log.warn("Unable to get JWT Token");
        } catch (ExpiredJwtException e) {
            log.warn("JWT Token has expired");
        }
    } else {
        log.warn("JWT Token does not begin with Bearer String");
    }

    if (username != null && SecurityContextHolder.getContext().getAuthentication() == null) {

        if (username.equals("scrapper-api")) {
            UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                    "scrapper-api", null, Arrays.asList());
            usernamePasswordAuthenticationToken
                    .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
            SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
        } else {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(username);
            // if token is valid configure Spring Security to manually set
            // authentication
            if (jwtTokenUtil.validateToken(jwtToken, userDetails)) {
                UsernamePasswordAuthenticationToken usernamePasswordAuthenticationToken = new UsernamePasswordAuthenticationToken(
                        userDetails, null, userDetails.getAuthorities());
                usernamePasswordAuthenticationToken
                        .setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                // After setting the Authentication in the context, we specify
                // that the current user is authenticated. So it passes the
                // Spring Security Configurations successfully.
                SecurityContextHolder.getContext().setAuthentication(usernamePasswordAuthenticationToken);
            }
        }
    }
    chain.doFilter(request, response);
}

Spring fox version is 3.0 Spring framework version is 2.7.0

1

There are 1 best solutions below

0
jodoro On BEST ANSWER

The solution was implementing a second WebSecurityConfigurerAdapter which will handle only swagger-ui/ paths

@Configuration
@Order(1)
public class SecurityConfig2 extends WebSecurityConfigurerAdapter {

@Autowired
PasswordEncoder encoder;

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.antMatcher("/swagger-ui/**")
            .authorizeRequests()
            .anyRequest().hasRole("FORM_USER")
            .and()
            .httpBasic();
}

// If you want to use in-memory authentication for testing
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.inMemoryAuthentication()
            .withUser("user")
            .password(encoder.encode("test"))
            .roles("FORM_USER");
}


}

This is using the basic in-memory authentication which was enough for my case but can be extended to use UserDetailsService

For more reference: How can I implement Basic Authentication with JWT authentication in Spring Boot?