401 while trying to access Swagger UI - Springdoc - spring

I was writing spring application.I added swagger into my project but somehow It couldn't run properly.Into my project also has bearer authentication with token. Please give me a hint How I might fix this problem
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.1.44</version>
</dependency>

Actually the problem is in your security setting. All resources/endpoints are protected by default when security is present on class path. What you need to do is to expose all resource that are needed for Swagger UI publicly. To do so you have at least two options. The first is to change or create configuration like this:
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter{
#Override
public void configure(WebSecurity web) throws Exception {
super.configure(web);
web.ignoring().antMatchers("swagger-ui/**", "swagger-ui**", "/v3/api-docs/**", "/v3/api-docs**");
}
By this you override whole HttpSecurity for mentioned paths means no CORS, CSRF, authorization will be checked.
The other option is to try Havelock. With the library you can expose swagger resource by one annotation.
Disclaimer: I am the founder and tech lead of the project

First of all use the last stable version.
This should help:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.4.4</version>
</dependency>
If the issue still persists, add more relevant information about your code to reproduce it.

Related

springboot swagger3 "Failed to load remote configuration."

Spring Boot 2.6.3 with Springdoc.
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-ui</artifactId>
<version>1.6.5</version>
</dependency>
In applicaton.yaml, when I set the path as /v3/api-docs or remove it, that means use the default path "/v3/api-docs".
The Swagger UI page shows up correctly with the APIs
http://localhost:8080/swagger-ui/index.html
But I want to overite the path as below
api-docs.path: /bus/v3/api-docs
then Swagger UI displays the "Failed to load remote configuration" error:
Make sure to add "/v3/api-docs/**" in configure method.
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/swagger-ui/**", "
/v3/api-docs/**");
}
}
If you are using Spring Security in your app, you must include the URL in the configs.
Add the code below please to your project.
#Configuration
public class WebSecurityConfiguration extends WebSecurityConfigurerAdapter {
#Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/swagger-ui/**", "/bus/v3/api-docs/**");
}
}
I had the same problem, If you are behind a reverse proxy, the fix was to add the following property in application.yml
server:
forward-headers-strategy: framework
this is needed due to the following
Swagger relies on internal routing to make requests from the clients perspective. Putting the service behind a reverse-proxy without providing the X-Forwarded headers will result in the user not being able to use the documentation as intended
source -> https://medium.com/swlh/swagger-spring-boot-2-with-a-reverse-proxy-in-docker-8a8795aa3da4
Perform "Empty cache and hard refresh" in your browser.
I think I have solved the problem (thanks to #Ivan Zaitsev), just wanted to add more clarification to the answer.
I too have changed the api-docs.path property and I had the same problem. When I inspect the requests on swagger UI page, swagger-config request returns 404 since it was still trying to get the config from the old URL.
Even though I have changed api-docs.path property, here is the request URL that tries to retrieve swagger-config.
http://localhost:8080/api/v3/api-docs/swagger-config
It turned out to be a problem related to openapi-ui, because I was able to solve it when I cleared the browser cache and cookies. It is better do to the tests with incognito browser since it does not hold any data on the session.
If you are using SpringBoot v3, you must use springdoc-openapi v2:
https://springdoc.org/v2/
With gradle, for example:
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.0.2'

How to use OpenApi annotations in spring-webflux RouterFunction endpoints?

I am currently working on a project where I use spring functional web programming. I usually use annotations of swagger 2 in restController but with functional web programming I can not find where ! The place to tell the app to do a search for endpoints (like basepackage in Docket) and load swagger in an html page.
Here is my code:
#Configuration
public class RouterClient{
#Bean
public RouterFunction<ServerResponse> routes(ClientHandler client){
return route(GET("/api/client"), client::findAll)
.andRoute(POST("/api/client"),client::add);
}
}
Config Class:
#Configuration
public class OpenApiConfiguration{
#Bean
public GroupedOpenApi groupOpenApi() {
String paths[] = {"/api/**"};
String packagesToscan[] = {"com.demo.client"};
return GroupedOpenApi.builder().setGroup("groups").pathsToMatch(paths).packagesToScan(packagesToscan)
.build();
}
}
The dependencies:
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webflux-core</artifactId>
<version>1.2.32</version>
</dependency>
<dependency>
<groupId>org.springdoc</groupId>
<artifactId>springdoc-openapi-webflux-ui</artifactId>
<version>1.2.32</version>
</dependency>
The result :
Functional endpoints are supported since 1.3.8 (early May). See releases on GitHub.
Have a look at this: https://springdoc.org/#spring-webfluxwebmvc-fn-with-functional-endpoints
The easiest way to see your endpoints on the Swagger UI is to add the #RouterOperation annotation to your RouterFunction methods (containing a single route), and specify the beanClass and beanMethod used in it. However, in your case, there are multiple routes on a single method, so you must also use the #RouterOperations annotation. These cases are well documented in the link above.
It seems like the current implementation of springdoc-openapi only allows to manually add the documentation.
set
springdoc.api-docs.enabled=false
This will skip classpath scanning (springfox) for the API annotations. (OAS3 replaced these in v3) and replace them with reading in the spec file (json/yaml).
Put the documentation in the Spec files, as one can generate any number of clients from these. Easiest way to start with legacy code is to copy the /api-docs/ files generated by springfox.
You can go to editor.swagger.io, load in the version 2 yaml and convert it to version 3 if springfox still doesn't do that. Then work with yaml files. (it's a contract UP-Front specification for a reason)
https://springdoc.org/
You need springdoc-openapi-webflux-ui and #RouterOperation.
spring-webflux with Functional Endpoints, will be available in the future release

WhyI am Getting 403 Forbidden error for actuator /refresh endpoint on Spring Boot 2 on Cloud Foundry{using Cloud Config Server service}

Within my project, I have the following bootstrap.properties file:
spring.application.name=vault-demo
management.endpoints.web.exposure.include=*
Additionally to that, I defined the following dependency:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-actuator</artifactId>
</dependency>
The config server is able to access the property but when I update that property in GitHub and POST to /refresh I get a 403: Forbidden. Do I need to make any change in my application or bootstrap.properties?
I got the solution, I needed to add a security configuration, for example:
#Configuration
#EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter{
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
}
Additionally, I had to add the following dependency:
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-rsa</artifactId>
<version>1.0.5.RELEASE</version>
</dependency>
I found this solution within the following GitHub issue:
https://github.com/spring-cloud/spring-cloud-config/issues/950
I notice that Spring Boot 2 cloud config dont need to be "hooked to /refresh endpoint" after commit (or other events), because the new version always request to remote git Server and compare the last commitId and if is diferrent commitId start to fetch the changes.
If debug and see the log traces, after request http://host:8888/{service}/{profile}/{label_branch} always ask github, and you will notice that if exist changes a "fetch proccess is started " , look at traces like github negotiation:
o.e.jgit.transport.PacketLineOut - git> want 4a766a1677....
o.e.jgit.transport.PacketLineOut - git> have 93cd4a98b5b3bb7d895...
and finally
o.e.jgit.transport.PacketLineOut - git> done
And after, the download:
o.e.jgit.transport.PacketLineIn - git< ACK 0f8d2413183d5.... common
and so on.
If you look traces and not exist changes (the last commitId is the same, the negotiation and download traces are not shown).
I think that is not a good performance behaviour, so would exist a property that disable it and therefore need a "forced refresh hook behaviour", but i couldn't find it on Spring boot 2.
On the other hand, I like it because you dont need to enable HTTP access to your config server to be notified, so the security configuration is not compromised.
I tried with Greenwich.RELEASE
Hope this helps and clarify this behaviour.

migrate to keycloak from spring boot security

i want to migrate to keycloak from my old spring boot security app.Below is my security config.
#Configuration
#EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter{
#Autowired
private CustomUserDetailsService customUserDetailsService;
#Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http
.authorizeRequests()
.antMatchers("/*", "/static/**", "/css/**", "/js/**", "/images/**").permitAll()
.antMatchers("/school-admin/*").hasAuthority("SCHOOL_ADMIN").anyRequest().fullyAuthenticated()
.antMatchers("/teacher/*").hasAuthority("TEACHER").anyRequest().fullyAuthenticated()
.anyRequest().authenticated().and()
.formLogin()
.loginPage("/login.html").defaultSuccessUrl("/loginSuccess.html")
.failureUrl("/login.html?error").permitAll().and()
.logout()
.logoutRequestMatcher(new AntPathRequestMatcher("/logout.html")).logoutSuccessUrl("/login.html?logout");
}
#Autowired
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(customUserDetailsService).passwordEncoder(new BCryptPasswordEncoder());
}
}
I have already installed the keycloak and it is running on port 8080.The problem I found out that, we should create role and user on keycloak admin page, But what my current system is, users and roles are on my MySQL DB. I don't want to insert the users and roles on keycloak for authentication and authorization.
Ok, obviously the first thing is a running keycloak instance, I assume this should be doable with the online documentation. We use i.e. Keycloak on a Wildfly instance.
Next step is to define a realm and at least one client in keycloak that you will use to connect to with your spring-boot application. In you application's POM you will need to add dependencies for a keylcoak adapter like i.e.
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-tomcat8-adapter</artifactId>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-spring-boot-adapter</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
The rest can be done in your application.properties, that's the place where you configure how the adapter connects to keycloak and which parts of your application should be secured. This can look like
keycloak.realm=myrealm #realm that you have created in keycloak, contains your client
keycloak.auth-server-url=KeycloakHOST:KeycloakPort/auth # Substitute with your settings
keycloak.ssl-required=none
keycloak.resource=myclient
#keycloak.use-resource-role-mappings=true
keycloak.enable-basic-auth=true # we use basic authentication in this example
keycloak.credentials.secret=2dcf74ca-4e4f-44bf-9774-6c32c12783d3 # Secret generated for you client in keycloak
keycloak.cors=true
keycloak.cors-allowed-headers=x-requested-with,origin,content-type,accept,authorization
keycloak.cors-allowed-methods=GET,POST,DELETE,PUT,OPTIONS
keycloak.cors-max-age=3600
keycloak.expose-token=true
keycloak.bearer-only=true
keycloak.securityConstraints[0].securityCollections[0].name=adminRule
keycloak.securityConstraints[0].securityCollections[0].authRoles[0]=SCHOOL_ADMIN
keycloak.securityConstraints[0].securityCollections[0].patterns[0]=/school-admin/*
keycloak.securityConstraints[1].securityCollections[0].name=teacherRule
keycloak.securityConstraints[1].securityCollections[0].authRoles[0]=TEACHER
keycloak.securityConstraints[1].securityCollections[0].patterns[0]=/teacher/*
That's basically all you need to do in your spring-boot application. All other endpoints not covered by the rules above remain available to all. You can find a pretty good tutorial on that here that is the longer version what I have described.

Spring Boot CSRF

Tried to implement CSRF protection on the latest Spring Boot.
All the examples on internet are based on user login and authentication, which I do not need.
My site does not have any sections requiring authentication.
I would like
1) Rest requests come from within site. No direct request from outside with wget to be allowed.
2) All pages (routes) must be requested from the index page (/)
Included the security dependency in pom.xml
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
-- Defined users in application.properties (even though, I do not need)
-- App creates _csrf.token .
-- Created class extending WebSecurityConfigurerAdapter with "configure" method overriding.
Tried all suggested filters in "configure". It did not work and finally left it blank.
The problem is that Wget can get api pages directly.
How to prevent it?
I've quickly put together a POC of this configuration:
#Configuration
#EnableWebSecurity
#SpringBootApplication
public class StackoverflowQ40929943Application extends WebSecurityConfigurerAdapter{
public static void main(String[] args) {
SpringApplication.run(StackoverflowQ40929943Application.class, args);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().antMatchers("/**").permitAll();
}
}
The gist of it is Spring Boot + Security will secure all endpoints automatically. Here we explicitly allow requests to all endpoints. But, Spring Boot + Security automatically configures CSRF out of the box which we've left enabled. Thus you get the best of both worlds.
NOTE: You'll probably need to refine this configuration further to meet your needs.
Full Example on GitHub

Resources