Adding authorization to Annotation-driven swagger.json with Jersey 2 and Spring Boot - spring-boot

I'm trying to add Basic Authentication to Swagger UI for a to a Swagger-annotated Jersey 2.0 web service built with Spring Boot. I'm using:
Spring Boot 1.5.4
spring-boot-starter-jersey
Swagger UI 3.0.4
(Maven package) swagger-jersey2-jaxrs 1.5.13
I'm able to generate a swagger.json file with the following JerseyConfig and with Swagger annotations on my Resources. This article was immensely helpful in getting this far.
#Component
public class JerseyConfiguration extends ResourceConfig {
private static Log logger = LogFactory.getLog(JerseyConfiguration.class);
#Value("${spring.jersey.application-path:/}")
private String apiPath;
public JerseyConfiguration() {
registerEndpoints();
configureSwagger();
}
private void registerEndpoints() {
register(MyEndpoints.class);
// Generate Jersey WADL at /<Jersey's servlet path>/application.wadl
register(WadlResource.class);
// Lets us get to static content like swagger
property(ServletProperties.FILTER_STATIC_CONTENT_REGEX, "((/swagger/.*)|(.*\\.html))");
}
/**
* Configure the Swagger documentation for this API.
*/
private void configureSwagger() {
// Creates file at localhost:port/swagger.json
this.register(ApiListingResource.class);
this.register(SwaggerSerializers.class);
BeanConfig config = new BeanConfig();
config.setConfigId("example-jersey-app");
config.setTitle("Spring Boot + Jersey + Swagger");
config.setVersion("2");
config.setContact("Me <me#example.com>");
config.setSchemes(new String[] {"http", "https"});
config.setResourcePackage("com.example.api");
config.setBasePath(this.apiPath);
config.setPrettyPrint(true);
config.setScan(true);
}
}
Now I want to be able to use Basic Authentication to connect to these services from Swagger UI. I've configured it in Spring and can use it to authenticate to the site, but not from Swagger UI.
Unfortunately, none of the Spring Boot examples currently on the Swagger sample site include Jersey and authentication, and none of the Jersey examples use Spring Boot and #SpringBootApplication like I'm using on in my project.
How do I get Basic Auth to show up in the Swagger UI?

I was able to get this to work by adding ServletConfigAware to JerseyConfiguration. Then I could use the same style of Swagger configuration used in the Swagger Bootstrap.java examples.
#Component
public class JerseyConfiguration extends ResourceConfig implements ServletConfigAware{
private ServletConfig servletConfig;
// ... this is all unchanged ...
/**
* Configure the Swagger documentation for this API.
*/
private void configureSwagger() {
// Creates file at localhost:port/swagger.json
this.register(ApiListingResource.class);
this.register(SwaggerSerializers.class);
BeanConfig config = new BeanConfig();
// ... this is all unchanged ...
config.setScan(true);
Swagger swagger = new Swagger();
swagger.securityDefinition("basicAuth", new BasicAuthDefinition());
new SwaggerContextService().withServletConfig(servletConfig).updateSwagger(swagger);
}
#Override
public void setServletConfig(ServletConfig servletConfig) {
logger.info("Setting ServletConfig");
this.servletConfig = servletConfig;
}
}
After making these changes, and adding annotations like the following to my endpoints:
#Api(value = "/api", description = "My super API",
authorizations = {#Authorization(value="basicAuth")})
#Path("api")
#Component
public class MyApi {
I saw the following changes:
Added to my swagger.json:
"securityDefinitions":{"basicAuth":{"type":"basic"}}
...
"security":[{"basicAuth":[]}]}}
Also, in Swagger UI, a new green button appeared in the same row as the Schemes dropdown, that says "Authorize" with an open lock on it. If I click on it, a popup shows up where I can enter the username and password. Now those credentials are sent to the API when I use the Swagger UI "Try It" feature.

Related

How to make Spring Boot Reactive endpoints visible to SpringDoc OpenApi

I am working on a new Spring Boot reactive server application. The application exposes reactive endpoints as shown below:
#Configuration
public class XXXXRouter {
#Bean
public RouterFunction<ServerResponse> routes(ClaimsHandler handler) {
return nest(path("/api/xxxx"), nestedRoutes(handler));
}
private static RouterFunction<ServerResponse> nestedRoutes(xxxxHandler handler) {
return route(GET("/"), handler::allClaims)
.andRoute(GET("/{id}"), handler::byId)
.andRoute(GET("/{id}/notes"), handler::notesById);
}
}
I need to make these endpoints to swagger-ui like framework. I am using following dependencies to generate required swagger-ui and api-docs:
implementation 'org.springdoc:springdoc-openapi-webflux-core:1.2.32'
implementation 'org.springdoc:springdoc-openapi-webflux-ui:1.2.32'
I also have the following API config:
#Configuration
public class OpenAPIConfig {
#Bean
public OpenAPI customOpenAPI() {
return new OpenAPI().components(new Components()).info(new Info().title("Contact Application API")
.description("This is a sample Spring Boot RESTful service using springdoc-openapi and OpenAPI 3."));
}
}
localhost:8080/swagger-ui.html shows swagger-ui page. But, endpoints are not shown there.
Here is the output from localhost:8080/v3/api-docs:
{"openapi":"3.0.1","info":{"title":"Contact Application API","description":"This is a sample Spring Boot RESTful service using springdoc-openapi and OpenAPI 3."},"servers":[{"url":"http://localhost:8080","description":"Generated server url"}],"paths":{},"components":{}}
My question is how do we make the reactive endpoints available to swagger-ui.html?

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

Does Spring Boot Actuator have a Java API?

We customize the Spring Boot Actuator Info endpoint to include the application version number generated during our Jenkins build. We're using gradle to do this:
if (project.hasProperty('BUILD_NUMBER')) {
version = "${BUILD_NUMBER}"
} else {
version = "0.0.1-SNAPSHOT"
}
That works great for adding the version to the /info endpoint, but I'd like to access it when the application starts and print it to the application log.
I'm hoping the values are exposed in some property value (similar to spring.profiles.active) or through a Java API. That way, I could do something like this:
public class MyApplication{
public static void main(String[] args) throws Exception {
SpringApplication.run(MyApplication.class, args);
ConfigurableEnvironment environment = applicationContext.getEnvironment();
System.out.println(environment.getProperty("spring.fancy.path.to.info.version"));
}
}
Looking through the docs, I'm not finding a way to access these values easily in code. Has anyone else had luck with this?
To get exactly the same properties of an actuator endpoint that are exposed through the REST endpoints, you can inject in one of your classes an instance of the respective endpoint class. In your case, the "right" endpoint class would be the InfoEndpoint. There are analogous endpoint classes for metrics, health, etc.
The interface has changed a little between Spring Boot 1.5.x and Spring Boot 2.x. So the exact fully qualified class name or read method name may vary based on the Spring Boot version that you are using. In Boot 1.5.x, you can find most of the endpoints in the org.springframework.boot.actuate.endpoint package.
Roughly, this is how you could build a simple component for reading your version property (assuming that the name of the property inside the info endpoint is simply build.version):
#Component
public class VersionAccessor {
private final InfoEndpoint endpoint;
#Autowired
public VersionAccessor(InfoEndpoint endpoint) {
this.endpoint = endpoint;
}
public String getVersion() {
// Spring Boot 2.x
return String.valueOf(getValueFromMap(endpoint.info()));
// Spring Boot 1.x
return String.valueOf(getValueFromMap(endpoint.invoke()));
}
// the info returned from the endpoint may contain nested maps
// the exact steps for retrieving the right value depends on
// the exact property name(s). Here, we assume that we are
// interested in the build.version property
private Object getValueFromMap(Map<String, Object> info) {
return ((Map<String, Object>) info.get("build")).get("version");
}
}

Swagger 2 (Spring fox) adds 'es' to my API's

I was just trying to integrate Swagger into my Spring Boot (JAX-RS) project built with Gradle.I was able to generate a docker (Swagger UI) for the same as following :
I have configured my swagger with the default settings as follows :
package com.abc;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.annotation.Import;
import org.springframework.data.mongodb.repository.config.EnableMongoRepositories;
import springfox.documentation.swagger2.annotations.EnableSwagger2;
#EnableAutoConfiguration
#SpringBootApplication
#EnableMongoRepositories
#Slf4j
#Import({springfox.documentation.spring.data.rest.configuration.SpringDataRestConfiguration.class,springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration.class})
#EnableSwagger2
public class ServiceApplication {
public static void main(String[] args) {
SpringApplication.run(ServiceApplication.class, args);
}
public static void run(String[] args) throws Exception{
log.info("Started application on: 8080");
}
}
As we can see in the image for GET Events API the docker shows /eventses .. So from where it has added es to /events API which is written as :
#GET
public HashMap<String, Object> getEventList(#DefaultValue("1") #QueryParam("page") int page,
#DefaultValue("10") #QueryParam("rpp") int rpp, #QueryParam("events") String eventIds) {
HashMap<String, Object> eventsResultMap= new HashMap<String, Object>();
List<Events> events = null;
if (eventIds != null && eventIds.length() > 0) {
List<String> eventsIdList = Arrays.asList(eventIds.split(","));
log.info("" + eventsIdList);
events = eventService.getEvents(eventsIdList);
} else {
events = eventService.getEvents(page - 1, rpp);
}
eventsResultMap.put("EVENTS", events);
HashMap<String, Object> recordsMetaMap = new HashMap<String, Object>();
recordsMetaMap.put("total", eventService.totalCount());
recordsMetaMap.put("page", page);
recordsMetaMap.put("rpp", rpp);
eventsResultMap.put("_metadata", recordsMetaMap);
log.info("The events you have queried for are:" + eventsResultMap);
return eventsResultMap;
}
Please, guide me where I am doing wrong.What custom configs need to be done.
I have taken Reference from spring official documentation.
Everything in /eventses comes from Springfox's support for Spring Data REST and has nothing to do with the getEventList method in your controller. If you don't want to have auto-discovery of your entities like that, removing the class from the #Import line should do the trick.
If you are using a jax-rs implementation with spring boot, you should use swagger-core jax-rs libraries rather than spring fox. Swagger team has provided very detailed instructions here on how to configure your application for different implementations like jersey, rest-easy etc. I found it very easy to integrate for jersey 2.x.
To make your swagger documentation rich, you should try to provide as much meta data as you can using different swagger annotations as documented here. Swagger makes great use of these annotations combined with jax-rs annotations in some cases (E.g. QueryParam vs PathParam identification).
If you let me know which jax-rs implementation you are using, I might be able to provide you some sample configuration.
Edit:
For Jersey 2.x you will need to add something like this in your Jersey Configuration class (which extends org.glassfish.jersey.server.ResourceConfig):
#Bean
public BeanConfig swaggerConfig() {
register(ApiListingResource.class);
register(SwaggerSerializers.class);
BeanConfig config = new BeanConfig();
config.setConfigId("your-config-id");
config.setTitle( "Your Title" );
config.setSchemes(new String[] { "https", "http" });
config.setBasePath("your application base path E.g. /api");
config.setResourcePackage("package to be scanned E.g. com.example");
config.setPrettyPrint(true);
config.setScan(true);
return config;
}
Other than that, you will need to annotate your endpoint(service) classes with swagger annotations. E.g.
#Path("/material")
#Service
#Api(value = "Material")
public class MaterialEndpoint {
#POST
#ApiOperation(value = "Create Material")
#ApiResponses(value = { #ApiResponse(code = 201, message = "Success", response = CreateMaterialResponse.class),
#ApiResponse(code = 409, message = "Failure", response = ErrorResponse.class) })
public Response createMaterial(CreateMaterialRequest createMaterialRequest){
// Code goes here
}
}
And your entities with swagger annotations. It is upto you how rich you want your swagger documentation to be. Depending on that you can choose to annotate more or less classes.

Spring Boot with Spring Social Google provider

Any example how to integrate Spring Boot application with Spring Social Google (GabiAxel/spring-social-google) provider? I found this project, but it seems to be unfinished. Spring Boot explains how to get it working with Spring Facebook, Twitter, but is it the same for log in with Google?
As you have mentioned in your question, you can use that project hosted on github.
You can use this dependency
In a Configuration class, you will have to extend SocialConfigurerAdapter, override the addConnectionFactories method and add GoogleConnectionFactory. For example :
#Configuration
#EnableSocial
public class SocialConfig extends SocialConfigurerAdapter {
#Override
public void addConnectionFactories(ConnectionFactoryConfigurer connectionFactoryConfigurer, Environment environment) {
GoogleConnectionFactory googleConnectionFactory = new GoogleConnectionFactory(environment.getProperty("spring.social.google.app-id"), environment.getProperty("spring.social.google.app-secret"));
googleConnectionFactory.setScope("https://www.googleapis.com/auth/plus.login");
connectionFactoryConfigurer.addConnectionFactory(googleConnectionFactory);
}
#Bean
#Scope(value = "request", proxyMode = ScopedProxyMode.INTERFACES)
public Google google(ConnectionRepository repository) {
Connection<Google> connection = repository.findPrimaryConnection(Google.class);
return connection != null ? connection.getApi() : null;
}
}
You can use this along with the Spring Social examples.

Resources