Adding Actuator as a groupedOpenApi - spring

Could we add Actuator endpoints as a groupedOpenApi that will be gourped separately ?
ex :
#bean
public GroupedOpenApi actuatorApi() {
return GroupedOpenApi.builder().setGroup("Actuator")
.packagesToScan("org.springframework.boot.actuate")
.pathsToMatch("/actuator/**")
.build();
}
Thanks

First you need to enable actuator on the swagger-ui:
springdoc.show-actuator=true
You just need to declare GroupedOpenApi bean:
#Bean
public GroupedOpenApi actuatorApi(){
String[] paths = {"/actuator/**"};
return GroupedOpenApi.builder()
.setGroup("groups")
.pathsToMatch(paths)
.build();
}
Here are the steps to add actuator:
https://github.com/springdoc/springdoc-openapi-demos/commit/aa6bcf1f0312c8fc36f94aeb4653718b36c308f6

The solution provided by #brianbro mostly works but there is an issue where some endpoints that use parameters in URL, e.g. /actuator/metrics/{requiredMetricName} due to way spring boot handles the actuator endpoints (single handler method, no #PathParam) the PathParam fields don't show in Swagger. See Spring boot actuator endpoint parameters issue.
Example of what shows in Swagger without resolving the issue:
Example of what shows in Swagger after resolving the issue:
How to fix this is discussed in Adding Actuator as a groupedOpenApi but some of the links are broken. The key issue is there is an ActuatorOpenApiCustomiser class that is used to fix the PathParams for Actuator, and that class is not being called when Actuator resides within a GroupedOpenApi.
Full solution (working with springdoc:1.6.9)...
First you need to enable actuator on the swagger-ui:
springdoc.show-actuator=true
Declare GroupedOpenApi bean using code (you can't use the springdoc.group-configs[0] properties because you need to add a OpenApiCustomiser to the group):
#Bean
public GroupedOpenApi actuatorApi(OpenApiCustomiser actuatorOpenApiCustomiser){
String[] paths = {"/actuator/**"};
return GroupedOpenApi.builder()
.setGroup("Actuator")
.pathsToMatch(paths)
.addOpenApiCustomiser(actuatorOpenApiCustomiser)
.build();
}
Addtional Sample from SpringDoc

Related

How to disable interceptor call for Actuators in Springboot application

I am trying to implement Prometheus in my microservices based spring boot application, deployed over weblogic server. As part of POC,I have included the configs as part of one war. To enable it, i have set below config -
Application.properties
management:
endpoint:
prometheus:
enabled: true
endpoints:
web:
exposure:
include: "*"
Gradle -
implementation 'io.micrometer:micrometer-registry-prometheus'
But the actuator request is getting blocked by existing interceptors. It asks to pass values in headers specific to our project. Through postman(http:localhost:8080/abc/actuator/prometheus), I am able to test my POC(with required headers) and it returns time-series data expected by Prometheus. But Prometheus is not able to scrap data on its own(with pull approach), as the call lacks headers in request.
I tried following links (link1,link2) to bypass it, but my request still got intercepted by existing interceptor.
Interceptors blocking the request are part of dependent jars.
Edited --
I have used following way to exclude all calls to interceptor -
#Configuration
public class MyConfig implements WebMvcConfigurer{
#Override
public void addInterceptors(InterceptorRegistry registry){
registry.addInterceptor(new MyCustomInterceptor()).addPathPatterns("**/actuator/**");
}
}
MyCustomInterceptor
#Component
public class MyCustomInterceptor implements HandlerInterceptor{
}
I have not implemented anything custom in MyCustomInterceptor(as i only want to exclude all calls to 'actuator' endpoint from other interceptors).
#Configuration
public class ActuatorConfig extends WebMvcEndpointManagementContextConfiguration {
public WebMvcEndpointHandlerMapping webEndpointServletHandlerMapping(WebAnnotationEndpointDiscoverer endpointDiscoverer,
EndpointMediaTypes endpointMediaTypes,
CorsEndpointProperties corsProperties,
WebEndpointProperties webEndpointProperties) {
WebMvcEndpointHandlerMapping mapping = super.webEndpointServletHandlerMapping(
endpointDiscoverer,
endpointMediaTypes,
corsProperties,
webEndpointProperties);
mapping.setInterceptors(null);
return mapping;
}
}
Maybe you can override with setting null. I got code from https://github.com/spring-projects/spring-boot/issues/11234
AFAIK Spring HandlerInterceptor do not intercept actuator's endpoints by default.
Spring Boot can't intercept actuator access

Security is not added to Swagger from Open API generator

I am working on a new project in my team and we are implementing an API following the API first methodology. We are using openapi-generator-maven-plugin to generate our API from an yml file of format OpenAPI 3.0.3. To generate the swagger file we use springfox 2.9.2. The issue that I am facing is when I am trying to add security to the swagger for the requests.
components:
securitySchemes:
bearerAuth:
type: http
scheme: bearer
bearerFormat: JWT
security:
- bearerAuth: [ ]
The Authorize button doesn't appear in swagger page, only the lock near to the request appears but it doesn't do anything (see picture below).
What I observed is that if I open the /v2/api-docs the swagger json doesn't include the security definitions part.
The only way that I managed to add security is by adding by code in the Docket object the security part like so:
new Docket(DocumentationType.SWAGGER_2)
.securityContexts(Collections.singletonList(securityContext()))
.securitySchemes(Collections.singletonList(bearerJwtKey()))
.select()
.apis(RequestHandlerSelectors.basePackage("com.example"))
.paths(PathSelectors.any())
.build();
Is this the only way to add security to Swagger UI or am I missing something?
Reason: Bearer Auth isn't implemented in spring library yet :(
Workaround solution - extend generated Docket:
Import generated config class and then add a security schema (ApiKey) to the existing Docket bean. Example:
#Configuration
#Import(OpenAPIDocumentationConfig.class) // openapi generated config class
public class SwaggerConfiguration {
#Autowired
ApplicationContext context;
#PostConstruct
public void extendExistingDocketWithSecurity() {
Docket docket = context.getBean(Docket.class);
docker.securitySchemes(Collections.singletonList(bearer()));
}
private static ApiKey bearer() {
// where "bearerAuth" - name of your schema in YML spec. file
return new ApiKey ("bearerAuth", HttpHeaders.AUTHORIZATION, "header");
}
Done! You're awesome!
Now you're using generated swagger config without overriding, but just extending

Spring Boot 2 Actuator without Spring Boot and #EnableAutoConfiguration

I am trying to set up Spring Actuator with existing Gradle Spring MVC project. I am not able to use #EnableAutoConfiguration.
Unfortunately, I am not able to reach actuator endpoints, I think I am missing something.
The Spring dependencies in the project are:
// springVersion = 5.1.+
implementation(
"org.springframework:spring-beans:$springVersion",
"org.springframework:spring-webmvc:$springVersion",
"org.springframework:spring-jdbc:$springVersion")
implementation 'org.springframework.boot:spring-boot-starter-actuator'
I am trying to configure project with following:
#Configuration
#Import({EndpointAutoConfiguration.class,
MetricsEndpointAutoConfiguration.class,
HealthEndpointAutoConfiguration.class,
MappingsEndpointAutoConfiguration.class,
InfoEndpointAutoConfiguration.class})
#EnableWebMvc
public class DI_App {
}
In properties file, I added:
management.endpoints.web.exposure.include=*
Non of actuator endpoints is enabled, I am getting 404 when trying to access them.
I went through many related questions, but non of the solutions worked for me.
I might need to define custom EndpointHandlerMapping but not sure how to do this, it seems unavailable.
(Ref: https://stackoverflow.com/a/53010693)
EDIT:
Currently, my app config looks like this:
#Configuration
#EnableWebMvc
#ComponentScan("com.test.springtest")
#Import({
ConfigurationPropertiesReportEndpointAutoConfiguration.class,
EndpointAutoConfiguration.class,
WebEndpointAutoConfiguration.class,
HealthEndpointAutoConfiguration.class,
HealthIndicatorAutoConfiguration.class,
InfoEndpointAutoConfiguration.class,
InfoContributorAutoConfiguration.class,
LogFileWebEndpointAutoConfiguration.class,
LoggersEndpointAutoConfiguration.class,
WebMvcMetricsAutoConfiguration.class,
ManagementWebSecurityAutoConfiguration.class,
ManagementContextAutoConfiguration.class,
ServletManagementContextAutoConfiguration.class
})
public class DI_App {
private final ApplicationContext _applicationContext;
DI_App(ApplicationContext applicationContext) {
_applicationContext = applicationContext;
System.setProperty("management.endpoints.web.exposure.include", "*");
System.setProperty("management.endpoints.jmx.exposure.exclude", "*");
System.setProperty("management.endpoints.web.base-path", "/manage");
System.setProperty("management.server.port", "10100");
}
#Bean
public WebMvcEndpointHandlerMapping endpointHandlerMapping(Collection<ExposableWebEndpoint> endpoints) {
List<String> mediaTypes = List.of(MediaType.APPLICATION_JSON_VALUE, ActuatorMediaType.V2_JSON);
EndpointMediaTypes endpointMediaTypes = new EndpointMediaTypes(mediaTypes, mediaTypes);
WebEndpointDiscoverer discoverer = new WebEndpointDiscoverer(_applicationContext,
new ConversionServiceParameterValueMapper(),
endpointMediaTypes,
List.of(EndpointId::toString),
emptyList(),
emptyList());
return new WebMvcEndpointHandlerMapping(new EndpointMapping("/manage"),
endpoints,
endpointMediaTypes,
new CorsConfiguration(),
new EndpointLinksResolver(discoverer.getEndpoints()));
}
}
I had to add dispatcherServlet bean, in order to be able to add ManagementContextAutoConfiguration.class to Imports:
#Component
public class AppDispatcherServlet implements DispatcherServletPath {
#Override
public String getPath() {
return "/";
}
}
Current state is that when going to /manage endpoint I get this:
{"_links":{"self":{"href":"http://localhost:10100/dev/manage","templated":false},"info":{"href":"http://localhost:10100/dev/manage/info","templated":false}}}
But http://localhost:10100/dev/manage/info returns 404 and no other endpoints are available.
I'm using Maven, not Gradle, but was in a similar situation. I had a working spring-boot-actuator 1.4.2.RELEASE Health actuator endpoint with Spring MVC 4.3.21. Upgraded to spring-boot-starter-actuator 2.6.1 and Spring MVC 5.3.13 and the following works for me to reach /myAppContext/health.
The DispatcherServletAutoConfiguration import may be able to replace your explicit DispatcherServlet bean. My case doesn't include the Info actuator endpoint but the key thing for me was the specific Imports below. Order is somewhat important for certain imports, at least in my testing.
I know very little about spring boot so this is the result of enabling auto configuration, pouring through spring boot TRACE log output, and trying lots of different import combinations.
#Configuration
#EnableWebMvc
#Import({
DispatcherServletAutoConfiguration.class,
WebMvcAutoConfiguration.class,
WebEndpointAutoConfiguration.class,
EndpointAutoConfiguration.class,
HealthEndpointAutoConfiguration.class,
WebMvcEndpointManagementContextConfiguration.class
})
#PropertySource("classpath:/health.properties")
public class MyAppActuatorConfig {
// 1.x version had EndpointHandlerMapping and HealthMvcEndpoint beans here.
// There may be a more spring-boot-ish way to get this done : )
}
And a minimal health.properties that suited my deployment specifics where security was already in place:
management.endpoints.web.base-path=/
management.endpoint.health.show-details=when-authorized
management.endpoint.health.show-components=when-authorized

spring boot 2 + netty + servlet.context-path + not working

I am trying to create a spring-boot-2 REST api using spring-boot-starter-webflux and reactive Netty. I am trying to set the context-path as per the new properties to be defined in application.yml defined in Spring-Boot-2.
server.servlet.context-path: /api # Define the server context path
However it looks like Webflux, Netty doesn't use/recognise this property defined in application.yml.
If I use spring-boot-starter-web and Tomcat as the default server then it works fine and recognises context-path properly.
Didn't find anything mentioned about Netty's context-path in Spring Boot 2 documentation.
Spring Boot Version = 2.0.3.RELEASE
Please let me know if I missed something or this is the default behaviour of Webflux Netty ?
Configuring the context path is servlet-specific. when using WebFlux,
the configuration property was renamed to server.servlet.context-path and only for servlet based deployment.
You can read below thread to how you can deal with context path in webflux, please see comment
https://github.com/spring-projects/spring-boot/issues/10129#issuecomment-351953449
Webflux Context path issue thread
In spring boot 2.3.x you can set spring.webflux.base-path property
It worked for me with
spring.webflux.base-path=/myPath
but only when adding the hint in this comment: https://stackoverflow.com/a/67840678/8376373
which suggests to inject a WebFluxProperties Bean
#Bean
fun webFluxProperties(): WebFluxProperties {
return WebFluxProperties()
}
You can use a WebFilter to work around this limitation:
#Autowired
lateinit var serverProperties: ServerProperties
#Bean
fun contextPathWebFilter(): WebFilter {
val contextPath = serverProperties.servlet.contextPath
return WebFilter { exchange, chain ->
val request = exchange.request
if (request.uri.path.startsWith(contextPath)) {
chain.filter(
exchange.mutate()
.request(request.mutate().contextPath(contextPath).build())
.build())
} else {
chain.filter(exchange)
}
}
}

Hide Feign client endpoints in Swagger

I am using Springboot autoconfiguration, and currently all my Feign endpoints are exposed in swagger-ui. How can I disable this feature?
You can set this in your application.properties as:
endpoints.enabled=false
endpoints.health.enabled=true
endpoints.loggers.enabled=true
In your case it will be something like
endpoints.feign.***=true
But this is not disabling for swagger but endpoints exposure themselves. For Swagger you have to markup them explicitly with #Api#hidden() for example.
So far the best way to not include unrelated endpoints is through Swagger Docker, e.g.
#Configuration
#EnableSwagger2
class SwaggerConf {
#Bean
Docket allApis() {
return new Docket(DocumentationType.SWAGGER_2)
.groupName("all")
.select().apis(RequestHandlerSelectors.basePackage("com.example.base"))
.build();
}
}
Simplest solution that worked for me is to add #ApiIgnore to the Feign Client
#ApiIgnore
#FeignClient()
public interface FeignApi {
}

Resources