Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to infer base url. This is common when using dynamic servlet registration or when the API is behind an API Gateway #2191

Closed
evser opened this issue Jan 16, 2018 · 39 comments

Comments

@evser
Copy link

evser commented Jan 16, 2018

After updating Swagger to 2.8.0, I started to experience this issue. I never faced this before.
#1865
Does anyone either?

@cpoissonnier
Copy link

cpoissonnier commented Jan 17, 2018

Make sure that all query are ok in developer console, I have the same issue, some of my queries return 403.

In my project, Swagger is behind basic auth (to prevent swagger to be public), but /swagger-resources/** routes are not called with Authorization header since I updated to Springfox 2.8.0

The workaround is to make this route public :
.antMatchers("/swagger-resources/**").permitAll()

@goodlifeinc
Copy link

goodlifeinc commented Jan 17, 2018

Well I am using Swagger 2.7.0 and this fix doesn't help.

Here is my security setup. Actuator endpoints are behind basicAuthentication.

http
	.csrf().disable()
		.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
	.and()
		.authorizeRequests()
			.antMatchers(actuatorPath + "/**").authenticated()
	.and()
		.httpBasic()
	.and()
		.authorizeRequests()
			.anyRequest().permitAll();

Stangest thing is same config in another project with same dependencies works fine.

EDIT

With a strange combination between @configuration and @EnableSwagger2 on SwaggerDocumentationConfig class, seems to have solved my issue.

@kasecato
Copy link
Contributor

@cpoissonnier An Authorization header will be added on the same-origin by #2189.

@evser
Copy link
Author

evser commented Jan 20, 2018

We should NOT disable security checks for swagger resources - as it also have sensitive data that should NOT be shown to any unknown user

@evser
Copy link
Author

evser commented Jan 20, 2018

BTW, here are my settings (I use cookies-based auth in my browser):

       protected void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
				.anyRequest().authenticated()
				.and().exceptionHandling().accessDeniedHandler(new AccessDeniedHandlerImpl())
				.and().logout().logoutSuccessHandler(new HttpStatusReturningLogoutSuccessHandler())
				.and().csrf().csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse())
				.and()
				.addFilterBefore(ssoFilter(ApplicationConfiguration.API_BASE_PATH + "/login"), BasicAuthenticationFilter.class)
				.requiresChannel().anyRequest().requireSecure();
	}

	@Bean
	public FilterRegistrationBean oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) {
		FilterRegistrationBean frb = new FilterRegistrationBean();
		frb.setFilter(filter);
		frb.setOrder(SecurityProperties.DEFAULT_FILTER_ORDER);
		return frb;
	}

	@Bean
	@ConfigurationProperties("oauth2.client")
	public OAuth2ProtectedResourceDetails authDetails() {
		return new AuthorizationCodeResourceDetails();
	}

	@Bean
	public SecurityConfiguration swaggerSecurityConfiguration() {
		return new SecurityConfiguration("client-id", "client-secret", "realm",
				"", "{{X-XSRF-COOKIE}}", ApiKeyVehicle.HEADER, "X-XSRF-TOKEN", ",");
	}

	private Filter ssoFilter(String path) {
		OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationFilter = new OAuth2ClientAuthenticationProcessingFilter(path);
		OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(authDetails(), oauth2ClientContext);
		DefaultRedirectStrategy defaultRedirectStrategy = new DefaultRedirectStrategy();
		oAuth2ClientAuthenticationFilter.setRestTemplate(oAuth2RestTemplate);
		oAuth2ClientAuthenticationFilter.setTokenServices(resourceServerTokenServices);
		oAuth2ClientAuthenticationFilter.setAuthenticationSuccessHandler(
				(request, response, authentication) -> {
					String redirectUrl = request.getParameter(REDIRECT_URL_PARAM);
					if (redirectUrl == null) {
						redirectUrl = DEFAULT_REDIRECT_URL;
					} else {
						if (!redirectUrlValidator.validateRedirectUrl(redirectUrl)) {
							request.setAttribute(MESSAGE_ATTRIBUTE_NAME,
									messageSource.getMessage("ivalid.redirect.url", new String[] { redirectUrl }, LocaleContextHolder.getLocale()));
							response.sendError(HttpStatus.FORBIDDEN.value());
						}
					}
					defaultRedirectStrategy.sendRedirect(request, response, redirectUrl);
				});
		return oAuth2ClientAuthenticationFilter;
	}

And Docket:

	@Bean
	public Docket api() throws IOException, URISyntaxException {
		final List<ResponseMessage> globalResponses = Arrays.asList(
				new ResponseMessageBuilder()
						.code(200)
						.message("OK")
						.build(),
				new ResponseMessageBuilder()
						.code(400)
						.message("Bad Request")
						.build(),
				new ResponseMessageBuilder()
						.code(500)
						.message("Internal Error")
						.build());
		final ApiInfo apiInfo = new ApiInfo("REST API", new BufferedReader(new InputStreamReader(getClass().getResourceAsStream(CHANGELOG_FILENAME)))
				.lines()
				.collect(Collectors.joining(System.lineSeparator())),
				"1.0.0-RC1", "", new Contact("team", "", "bla@bla.com"), "", "", Collections.emptyList());
		return EnvironmentUtils
				.applyIfNotStaging(
						new Docket(DocumentationType.SWAGGER_2),
						docket -> docket.securitySchemes(Arrays.asList(new ApiKey("Token Access", HttpHeaders.AUTHORIZATION, In.HEADER.name()))))
				.useDefaultResponseMessages(false)
				.globalResponseMessage(RequestMethod.GET, globalResponses)
				.globalResponseMessage(RequestMethod.POST, globalResponses)
				.globalResponseMessage(RequestMethod.DELETE, globalResponses)
				.globalResponseMessage(RequestMethod.PATCH, globalResponses)
				.select()
				.apis(RequestHandlerSelectors.basePackage("com.controller"))
				.build()
				.apiInfo(apiInfo)
				.directModelSubstitute(Temporal.class, String.class);
	}

@Hronom
Copy link

Hronom commented Jan 26, 2018

Same here what the status of pull request?
My application is protected by basic auth using api gateway.

@dilipkrish
Copy link
Member

@evser thanks for sharing your configuration. You are absolutely correct about not unauthenticated users access to specification resources

@crazy-airhead
Copy link

Maybe Help. I found that the Springboot Application Class need to add @EnableSwagger2 annotation.

@seetharamani
Copy link

Does this issue have been figured out?? Once i upgraded to 2.8.0 from 2.6.1, the swagger ui started showing the error "Unable to infer base url".

When I look at debug logs, i do see this line.

{"category":"org.springframework.boot.web.filter.OrderedRequestContextFilter","severity":"DEBUG","text":"Bound request context to thread: Request(GET //localhost:10780/my-service/api/null/null/swagger-resources)@5689340d"},"v":"1"}

Why the base url for the swagger-resources are messed up - no idea! I tried debugging, and when i step in I do see the context path of my application is right, which is /my-service.

Any help is appreciated.

@dilipkrish
Copy link
Member

Not sure. Would be great if you could share your repository

@AlexRosier
Copy link

AlexRosier commented Mar 16, 2018

I have the same issue using spring security with basic authentication. What avoided the issues is adding

protected void configure(HttpSecurity http) throws Exception {
        http.authorizeRequests()
                .antMatchers(
                                "/v2/api-docs",
                                 "/swagger-resources", 
                                "/swagger-resources/configuration/ui", 
                                "/swagger-resources/configuration/security")
                .permitAll()

But this removes all security of those endpoints. An other solution is setting the Authorization header with the basic authentication.
But what I think should happen is the basic authentication pop-up is shown before the "Unable to infer base url" pop-up

@dilipkrish
Copy link
Member

@AlexRosier I think you need to protect the swagger resources as well starting from swagger-ui

@ghost ghost removed the next label Apr 1, 2018
@marcoblos
Copy link

Hi!

I follow the recomendations in this post and solved the problem.

With the code bellow I can make calls to my rest API ignoring the WWW-Authenticate headers and use this headers only in swagger context (e.g.: localhost:8080/swagger-ui.html) to ask to user your username and password (I used Basic Authentication in this example).

This code protects:

  • /swagger-resources/** with BasicAuthenticationEntryPoint
  • /swagger-ui.html** with BasicAuthenticationEntryPoint
  • "/webjars/** with BasicAuthenticationEntryPoint
  • /** with RestAuthenticationEntryPoint (this is a custom entry point)

In pom.xml

...
<repositories>
    <repository>
        <id>swagger</id>
        <name>swagger</name>
        <url>http://oss.jfrog.org/artifactory/oss-snapshot-local</url>
    </repository>
</repositories>
...
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger2</artifactId>
    <version>2.8.1-SNAPSHOT</version>
</dependency>
<dependency>
    <groupId>io.springfox</groupId>
    <artifactId>springfox-swagger-ui</artifactId>
    <version>2.8.1-SNAPSHOT</version>
</dependency>
...

Class that extends WebSecurityConfigAdapter:

@Configuration
public class WebSecurityConfigEntryPointApplication extends WebSecurityConfigurerAdapter {

    private static final List<String> AUTH_LIST = Arrays.asList(
            "/swagger-resources/**",
            "/swagger-ui.html**",
            "/webjars/**",
            "favicon.ico");

    @Autowired
    private RestAuthenticationEntryPoint restAuthenticationEntryPoint;

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .antMatcher("/**").authorizeRequests().anyRequest().authenticated()
                .and()
                .exceptionHandling()
                .defaultAuthenticationEntryPointFor(swaggerAuthenticationEntryPoint(), new CustomRequestMatcher(AUTH_LIST))
                .and()
                .httpBasic()
                .authenticationEntryPoint(restAuthenticationEntryPoint)
                .and()
                .csrf().disable();
    }

    @Bean
    public BasicAuthenticationEntryPoint swaggerAuthenticationEntryPoint() {
        BasicAuthenticationEntryPoint entryPoint = new BasicAuthenticationEntryPoint();
        entryPoint.setRealmName("Swagger Realm");
        return entryPoint;
    }

    private class CustomRequestMatcher implements RequestMatcher {

        private List<AntPathRequestMatcher> matchers;

        private CustomRequestMatcher(List<String> matchers) {
            this.matchers = matchers.stream().map(AntPathRequestMatcher::new).collect(Collectors.toList());
        }

        @Override
        public boolean matches(HttpServletRequest request) {
            return matchers.stream().anyMatch(a -> a.matches(request));
        }

    }

}

RestAuthenticationEntryPoint:

@Component
public class RestAuthenticationEntryPoint implements AuthenticationEntryPoint {

	@Override
	public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException {
		response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Unauthorized");
	}
}

@zueski
Copy link

zueski commented Apr 19, 2018

I am facing the same issue. I have my app protected with session cookie with SAML authentication. I can get in to /swagger-ui.html, which does a request to /swagger-resources/configuration/ui. This is failing due to the cookie not being attached to the call. If it navigate to /swagger-resources/configuration/ui directly, it works. Is there a way to configure swagger-ui.html to pass the authentication on in the ajax call?

@dilipkrish
Copy link
Member

@zueski your issue should be fixed in the upcoming release of 2.9.0

@dilipkrish dilipkrish added this to the 2.9.0 milestone Apr 21, 2018
@zueski
Copy link

zueski commented Apr 25, 2018

Thanks @dilipkrish -- In the meantime, I have added this to my application.yml to work around this:

security:
  ignored: /swagger-resources/**

@dilipkrish
Copy link
Member

@zueski FYI 2.9.0 is released

@Hronom
Copy link

Hronom commented Apr 25, 2018

@dilipkrish Not see it in maven yet... need wait till maven central publish?

@dilipkrish
Copy link
Member

@Hronom Its available in jcenter for now.

<repositories>
    <repository>
      <id>jcenter</id>
      <url>https://jcenter.bintray.com/</url>
    </repository>
</repositories>

There is an issue getting it released in maven central that Im working through.

@CarstenHS
Copy link

I've fought this issue a lot (due to bad logging capabilities I believe) and will share my findings here.

My setup:

  • omitting some irrelevant stuff due to secrecy.

Spring boot 2.0.0.RELEASE
implementation 'io.springfox:springfox-swagger2:2.9.0'
implementation 'io.springfox:springfox-swagger-ui:2.9.0'

dependencyManagement {
imports {
mavenBom 'org.springframework.cloud:spring-cloud-dependencies:Finchley.M9'
}
}

I have two filterchains:
1: catching "swagger-ui.html" and creating a session for GUI interfacing. (comes before 2.)
2: REST filter for all requests REST interfacing.

Swagger filter config:
@OverRide
public void configure(WebSecurity web) {
web.ignoring().antMatchers("/error");
}

@Override
protected void configure(HttpSecurity http) throws Exception {
        .antMatchers(AUTH_WHITELIST).permitAll()
}

// AUTH_WHITELIST as mentioned above in this thread - without "/error"

REST filter
Add the AUTH_WHITELIST (now including "/error") to both WebSecurity.ignore() and to HttpSecurity.antMatchers.permitAll()

NOTE:
Make sure if you apply any authentication filters that they lie before
AnonymousAuthenticationFilter
SessionManagementFilter

Hope this helps ya out! :)

@dilipkrish
Copy link
Member

dilipkrish commented May 31, 2018

@CarstenHS thank you for sharing. This is probably one of the most sought after solutions for problems related to not rendering swagger-ui.

@lcareto
Copy link

lcareto commented Jun 12, 2018

Nothing related to Spring Security configuration, but I had the same issue and I fixed it, by changing this :

@RestControllerAdvice
public class MyResponseBodyAdvice implements ResponseBodyAdvice<ResponseWrapper> {
}

to

@RestControllerAdvice("my.super.package")
public class MyResponseBodyAdvice implements ResponseBodyAdvice<ResponseWrapper> {
}

Without adding restriction on base package to scan, in annotation @RestControllerAdvice, I guess it scans also all the package dependencies, and tries to cast all the ResponseBody to the defined type (in my case ResponseWrapper).

I'm running Spring Boot 2.0.2.RELEASE and Swagger 2.8.0; Springfox update to 2.9.0 didn't fix my problem.

@dilipkrish
Copy link
Member

Thanks for letting us know @lcareto!

@HamedKaramoko
Copy link

If after all attempt, your issue is not solved try to remove the property

server.servlet.path

in your spring boot application.properties.

Hope that will helps you guys. ;)

@dilipkrish
Copy link
Member

Thanks for the tip @HamedKaramoko

@dschulten
Copy link
Contributor

dschulten commented Oct 27, 2018

I had to apply @EnableSwagger2WebFlux or @EnableSwagger2WebMvc on my spring-boot Application.java, depending on it being in an mvc or webflux project. The EnableSwagger2 annotation is gone in the current code base 3.0.0-SNAPSHOT.

@dilipkrish
Copy link
Member

@dschulten just FYI, it is but it is still not written in stone (still a SNAPSHOT), If the usability implies it remain for upgrade paths etc. Im open to bringing it back.

@luksrn
Copy link

luksrn commented Dec 6, 2018

Hey guys, in my case it was a ResponseBodyAdvice that changed the response body of /v2/api-docs endpoint. I fixed the advice and the ui was rendered as expected.

@dilipkrish
Copy link
Member

@luksrn thanks for clarifying!

@akuma8
Copy link

akuma8 commented Jan 13, 2019

Sorry to open this issue but I am facing the same issue just after changing the static resource path from spring.mvc.static-path-pattern=/** to spring.mvc.static-path-pattern=/app-resources/**.
swagger

@MehmetMelik
Copy link

Clearing the browser cache in chrome fixed the issue. This may sound weird but this is what solved the problem in my case.

@sidhjhawar
Copy link

Clearing the browser cache in chrome fixed the issue. This may sound weird but this is what solved the problem in my case.

Yes, I just used incognito mode to open the swagger-ui and it worked fine.

@rakesh415
Copy link

Thanks @dilipkrish -- In the meantime, I have added this to my application.yml to work around this:

security:
  ignored: /swagger-resources/**

It worked for me after adding above lines. But what if I need some security to my applications.

@MohSalah90
Copy link

Nothing related to Spring Security configuration, but I had the same issue and I fixed it, by changing this :

@RestControllerAdvice
public class MyResponseBodyAdvice implements ResponseBodyAdvice<ResponseWrapper> {
}

to

@RestControllerAdvice("my.super.package")
public class MyResponseBodyAdvice implements ResponseBodyAdvice<ResponseWrapper> {
}

Without adding restriction on base package to scan, in annotation @RestControllerAdvice, I guess it scans also all the package dependencies, and tries to cast all the ResponseBody to the defined type (in my case ResponseWrapper).

I'm running Spring Boot 2.0.2.RELEASE and Swagger 2.8.0; Springfox update to 2.9.0 didn't fix my problem.

This solved my issue, thank you for sharing Bro.

@hacki11
Copy link

hacki11 commented Aug 30, 2019

this was helpful for me, using my own swagger.json with springfox-swagger-ui:
indrabasak/springfox-ui-from-json-example#2

@JakeWoki
Copy link

JakeWoki commented Jul 5, 2021

@evser
using Spring Security,how to add login/logout document?

@MurilloNacfur
Copy link

Here it's worked : http://localhost:8080/swagger-ui/index.html

@hasitha3rd
Copy link

I was stuck for a day with this issue. My issue was incorrect port configuration. Check your application.yml/application.properties file for port configuration. There I had mistakenly added both
server.port , management.server.port with different values 🤣 .

@miladmofidi
Copy link

miladmofidi commented Apr 26, 2022

I have the same issue, when I open swagger UI URL: http://192.168.32.241:31650/swagger-ui.html , appear this error I read the comments but I could not solve my issue.

my SwaggerConfig.java is:

`@Configuration
@EnableSwagger2
public class SwaggerConfig
{
    public static final String SWAGGER_SCAN_BASE_PACKAGE = "com.some.core.controller";

    @Bean
    public Docket SpringFoxConfig()
    {
        return new Docket(DocumentationType.SWAGGER_2)
                .select()
                .apis(RequestHandlerSelectors.basePackage(SWAGGER_SCAN_BASE_PACKAGE))
                .paths(regex("/tmf-api/ServiceActivationAndConfiguration/v4/service.*"))
                .build()
                .apiInfo(metaData()).securitySchemes(Collections.singletonList(apiKey()))
                .securityContexts(Collections.singletonList(securityContext()));
    }

    private ApiInfo metaData()
    {
        return new ApiInfoBuilder().version("1.0.0").title("title")
                .description("desc").contact(
                        new Contact("contact",
                                    "contact"))
                .build();
    }

    private SecurityContext securityContext()
    {
        return SecurityContext.builder().securityReferences(defaultAuth()).forPaths(PathSelectors.regex("/.*")).build();
    }

    private List<SecurityReference> defaultAuth()
    {
        final AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        final AuthorizationScope[] authorizationScopes = new AuthorizationScope[]{authorizationScope};
        return Collections.singletonList(new SecurityReference("JWT", authorizationScopes));
    }

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

And this is my SecurityConfig.java :

@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
{

    @SuppressWarnings("findsecbugs:SPRING_CSRF_PROTECTION_DISABLED")
    @Override
    protected void configure(HttpSecurity http) throws Exception
    {
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowedHeaders(List.of("Authorization", "Cache-Control", "Content-Type"));
        corsConfiguration.setAllowedOrigins(List.of("*"));
        corsConfiguration
                .setAllowedMethods(List.of("GET", "POST", "PUT", "DELETE", "PUT", "OPTIONS", "PATCH", "DELETE"));

        http.authorizeRequests().antMatchers("/**").permitAll().anyRequest()
                .authenticated().and().csrf().disable().cors().configurationSource(request -> corsConfiguration)
        ;
    }
}

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests