How to show Spring Security Username Password Authentication Filter url in Swagger-ui?

Viewed 351

I am using Spring Security and using Username Password Authentication Filter. I want to know if it is possible to show the authentication endpoint in Swagger. This endpoint is generated automatically by the filter (as far I understood).

I really want to make this endpoint appear in Swagger-ui, otherwise I will need to login in Postman and then use Swagger with the Jwt Token, which is little strange.

This is the UsernamePasswordAuthenticationFilter:

public class AuthenticationFilter extends UsernamePasswordAuthenticationFilter {
private final AuthenticationManager authenticationManager;

public AuthenticationFilter(AuthenticationManager authenticationManager) {
    this.authenticationManager = authenticationManager;
}

@Override
public Authentication attemptAuthentication(HttpServletRequest req,
                                            HttpServletResponse res) {
    try {
        LoginDTO userEntity = new ObjectMapper().readValue(req.getInputStream(), LoginDTO.class);

        return authenticationManager.authenticate(
                new UsernamePasswordAuthenticationToken(userEntity.getEmail(),
                        userEntity.getPassword(), new ArrayList<>())
        );
    } catch (IOException e) {
        throw new RuntimeException(e);
    }
}

@Override
protected void successfulAuthentication(HttpServletRequest req, HttpServletResponse res, FilterChain chain,
                                        Authentication auth) throws IOException {
    Token token = new Token(JwtUtils.createAccessToken(ZonedDateTime.now().plusMinutes(10), TenantContext.getCurrentUserUniqueIdentifier(), TenantContext.getCurrentTenantId()),
            JwtUtils.createRefreshToken(ZonedDateTime.now().plusMonths(3)));
    PrintWriter out = res.getWriter();
    res.setContentType("application/json");
    res.setCharacterEncoding("UTF-8");
    out.print(new ObjectMapper().writeValueAsString(token));
    out.flush();
}

}

This is my class extending from WebSecurityAdapter. As you can see, I set the url as /v1/login.

@EnableWebSecurity
@AllArgsConstructor
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    private final UserEntityDetailsService userEntityDetailsService;
    private final BCryptPasswordEncoder bCryptPasswordEncoder;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.cors().and().csrf().disable().authorizeRequests()
                .antMatchers(HttpMethod.POST, "/v1/account").permitAll()
                .antMatchers(HttpMethod.GET, "/v1/healthcheck").permitAll()
                .antMatchers("/v1/recoverpassword/**").permitAll()
                .antMatchers("/swagger-ui/**", "/v2/api-docs", "/configuration/ui", "/swagger-resources/**", "/configuration/**", "/swagger-ui.html", "/webjars/**").permitAll()
                .anyRequest().authenticated()
                .and()
                .addFilter(getAuthenticationFilter())
                .addFilter(new AuthorizationFilter(authenticationManager()))
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
    }

    @Bean
    CorsConfigurationSource corsConfigurationSource() {
        final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", new CorsConfiguration().applyPermitDefaultValues());
        return source;
    }

    @Override
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userEntityDetailsService).passwordEncoder(bCryptPasswordEncoder);
    }

    public AuthenticationFilter getAuthenticationFilter() throws Exception {
        final AuthenticationFilter filter = new AuthenticationFilter(authenticationManager());
        filter.setFilterProcessesUrl("/v1/login");
        return filter;
    }
}

This is my SpringFox config:

@Configuration
@EnableSwagger2
public class SpringFoxConfig {

    private ApiInfo apiInfo() {
        return new ApiInfoBuilder()
                .title("Projeto List")
                .description("All endpoints of Projeto List Api")
                .build();
    }

    @Bean
    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
                .useDefaultResponseMessages(false)
                .apiInfo(apiInfo())
                .select()
                .apis(RequestHandlerSelectors.basePackage("br.com.projetolist.resource"))
                .paths(PathSelectors.ant("/**"))
                .build()
                .securitySchemes(Arrays.asList(apiKey()));
    }

    /**
     * SwaggerUI information
     */
    @Bean
    UiConfiguration uiConfig() {
        return UiConfigurationBuilder.builder()
                .deepLinking(true)
                .displayOperationId(false)
                .defaultModelsExpandDepth(1)
                .defaultModelExpandDepth(1)
                .defaultModelRendering(ModelRendering.MODEL)
                .displayRequestDuration(false)
                .docExpansion(DocExpansion.NONE)
                .filter(false)
                .maxDisplayedTags(null)
                .operationsSorter(OperationsSorter.ALPHA)
                .showExtensions(false)
                .tagsSorter(TagsSorter.ALPHA)
                .validatorUrl(null)
                .build();
    }

    private ApiKey apiKey() {
        return new ApiKey("jwtToken", "Authorization", "header");
    }

}
1 Answers

You can just add a similar method to one of your controllers. In your case, it will be the POST method with URL "/v1/login".

@PostMapping("/v1/login")
@ResponseStatus(OK)
fun login(@RequestBody userCreds: UserCredentials) {}
Related