Add Swagger Basic AUTH to Spring Boot App
Asked Answered
P

4

6

Requirements:

  • Spring Boot application with Springfox
  • Add BASIC authentication to Swagger
  • Pass on all other requests

Code: implemented

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/swagger-resources/*", "*.html", "/api/v1/swagger.json")
                .hasAuthority("SWAGGER")
                .anyRequest().permitAll()
            .and()
                .httpBasic()
            .and()
                .csrf().disable();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("admin").password("admin").authorities("SWAGGER");
    }
}

This code however does not work - you can freely browse /swagger-ui.html#/ without any authentcation.

Question is - why BASIC auth and user do not apply to swagger ui endpoint?

Paulita answered 25/4, 2018 at 14:2 Comment(1)
Of course it doesn't work, you're using .permitAll() instead of .authenticated()Jellaba
J
5

You should use the .authenticated() instead of .permitAll():

.authorizeRequests()
    .antMatchers("/swagger-resources/*", "*.html", "/api/v1/swagger.json")
        .hasRole("SWAGGER")
    .anyRequest()
        .authenticated()

This will:

  • Restrict access to all resources matching /swagger-resources/*, *.html and /api/v1/swagger.json

  • Allow unauthenticated access to all other resources

For clarification on why your configuration doesn't work, it's because you're not reading spring-security like you should be reading it.

Your old configuration reads like this:

.authorizeRequests() // allow requests
    .antMatchers(...) // that matches this
        .hasAuthority("SWAGGER") // with SWAGGER authority
    .anyRequest() // All requests above
        .permitAll() // grant full access 

In other words, you're granting full access to users with the SWAGGER authority, but what you've neglected is that by default, they already have access to it. To be more precise, everybody has access to it unless you specify otherwise.

By using .authenticated(). you're telling Spring that you want all requests matched to be restricted to people with the proper role or authority.

New configuration:

.authorizeRequests() // allow requests
    .antMatchers(...) // that matches this
        .hasRole("SWAGGER") // with role SWAGGER
    .anyRequest() // all requests above
        .authenticated() // needs authentication

Update

Regarding your issue with /swagger-resources, /swagger-resources/configuration/security and swagger-resources/configuration/ui returning 401:

You should replace /swagger-resources/* for /swagger-resources/**.

Update 2

Add the following at the end of your configuration to permit all non-matched requests:

.authorizeRequests()
    .anyRequest()
        .permitAll();
Jellaba answered 25/4, 2018 at 15:56 Comment(7)
I've started getting "Unable to infer base url. This is common when using dynamic servlet registration or when the API is behind an API Gateway. The base url is the root of where all the swagger resources are served." in browser. It should be something with ant matcher?Paulita
In addition, authentication works BUT swagger UI does not render. When swagger-ui.html loads, it invokes js script, which does 3 requests /swagger-resources, /swagger-resources/configuration/security, swagger-resources/configuration/ui. All of them result in 401. They do have a matcher and do open in browser. Please help.Paulita
/swagger-resources/* is not the case of 401, i think it is a bug in js, which does not provide AUTHORIZATION header. I've rolled back to different version and the header is provided.Paulita
@Paulita are you sure? /swagger-resources/* should not match /swagger-resources/configuration/security and /swagger-resources/configuration/security whereas /swagger-resources/** should.Jellaba
I'm using 2.2.6.1 version of springfox and it works. However, I have other problem - all other requests DO require basic auth now.Paulita
fixed by adding additional authorizeRequests fluent invocation in the end. .authorizeRequests().anyRequest().permitAll();Paulita
@Paulita I updated my answer with that the moment you wrote that :PJellaba
H
3

You could do something like below

Swagger

The code for swagger is like below.

    private List<SecurityScheme> basicScheme() {
        List<SecurityScheme> schemeList = new ArrayList<>();
        schemeList.add(new BasicAuth("basicAuth"));
        return schemeList;
    }

    public Docket api() {
        return new Docket(DocumentationType.SWAGGER_2)
            .
            .
            .
            .securitySchemes(basicScheme());
    }

Security Config

For the security config

    public void configureGlobal(final AuthenticationManagerBuilder auth)
        throws Exception {
        auth.inMemoryAuthentication()
                .withUser("USER")
                .password("PASSWORD")
                .roles("ADMIN");
    }
    .
    .
    .
    @Override
    protected void configure(final HttpSecurity httpSecurity) throws Exception {
        httpSecurity.csrf().disable().authorizeRequests()
    .anyRequest().authenticated().and().sessionManagement()
            .sessionCreationPolicy(SessionCreationPolicy.STATELESS)
            .and().httpBasic();
    }
    .
    .
    .
    @Override
    public void configure(final WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/v2/api-docs",
            "/configuration/ui",
            "/swagger-resources/**",
            "/webjars/**",
            "/configuration/security",
            "/swagger-ui.html");
    }

Controllers

Below passes the authorization to the methods using swagger.

   @PutMapping("/registration/{id}")
    @ApiOperation(value = "Update registration detail",
                  authorizations = { @Authorization(value="basicAuth") })
    public ResponseEntity<RegistrationModel> updateRegistration(

POM

and in your pom.xml, you will be needing:

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-security</artifactId>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger2</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>io.springfox</groupId>
            <artifactId>springfox-swagger-ui</artifactId>
            <version>2.9.2</version>
        </dependency>

That's basically it.

Heads answered 14/8, 2020 at 5:15 Comment(0)
T
1

Your configuration is strange. You can try something like that:

public static void configure(HttpSecurity http) throws Exception {
    http.csrf().disable()
    .antMatcher("/swagger-ui.html")
    .authorizeRequests()
        .anyRequest().hasAnyRole("SWAGGER")
        .and()
    .httpBasic();
}

This ensures authorization to swagger-ui.html path (with SWAGGER role).

Thralldom answered 25/4, 2018 at 14:33 Comment(2)
really? In my case I use it specifically to a restricted page. Try add security.basic.enabled=true in your application.propertiesThralldom
What if you try to match by "/swagger-ui*"? I remember there were some issues with antMatchers and page extensions, since they evaluate against servletPath + pathInfo (see AntPathRequestMatcher docs)Vatican
F
0

Ref- Spring Boot 3 + Basic Authentication Security + Swagger Example
The issue you are encountering is likely due to the fact that the Swagger UI HTML file and its associated resources are being served from a different context than the API endpoints. By default, Spring Security does not apply the same security rules to static resources like HTML files unless explicitly configured to do so.

To ensure that BASIC authentication is applied to the Swagger UI, you need to make sure that the security configuration covers the Swagger UI endpoints correctly.

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; 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;

@EnableWebSecurity
@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                .antMatchers("/swagger-ui.html", "/swagger-ui/**", "/v2/api-docs", "/swagger-resources/**", "/webjars/**")
                .hasAuthority("SWAGGER")
                .anyRequest().permitAll()
            .and()
                .httpBasic()
            .and()
                .csrf().disable();
    }

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("admin").password("{noop}admin").authorities("SWAGGER");
    }
}
Feldt answered 4/8, 2024 at 18:47 Comment(0)

© 2022 - 2025 — McMap. All rights reserved.