Swagger 2.0 where to declare Basic Auth Schema - swagger

How do I define basic authentication using Swagger 2.0 annotations and have it display in swagger UI.
In the resource I have:
#ApiOperation(value = "Return list of categories", response=Category.class, responseContainer="List", httpMethod="GET", authorizations = {#Authorization(value="basicAuth")})
public Response getCategories();
I looked here:
https://github.com/swagger-api/swagger-core/wiki/Annotations#authorization-authorizationscope
And it says "Once you've declared and configured which authorization schemes you support in your API, you can use these annotation to note which authorization scheme is required on a resource or a specific operation" But I can't find anything that talks about where to declare and configure the authorization schemes.
Update:
I found code on how to declare the schema, but I still do not see any information about the authentication schema in the UI. I'm not sure what I am missing
#SwaggerDefinition
public class MyApiDefinition implements ReaderListener {
public static final String BASIC_AUTH_SCHEME = "basicAuth";
#Override
public void beforeScan(Reader reader, Swagger swagger) {
}
#Override
public void afterScan(Reader reader, Swagger swagger) {
BasicAuthDefinition basicAuthDefinition = new BasicAuthDefinition();
swagger.addSecurityDefinition(BASIC_AUTH_SCHEME, basicAuthDefinition);
}
}

Using Springfox 2.6 annotations, you must first define Basic authentication as one of the security schemes when you set up the Docket in your configuration, like this:
List<SecurityScheme> schemeList = new ArrayList<>();
schemeList.add(new BasicAuth("basicAuth"));
return new
Docket(DocumentationType.SWAGGER_2).apiInfo(apiInfo)
.securitySchemes(schemeList)
...
Then you can use the Springfox annotations in your service to set Basic Auth for the operation for which you want to require authentication:
#ApiOperation(value = "Return list of categories", response=Category.class, responseContainer="List", httpMethod="GET", authorizations = {#Authorization(value="basicAuth")})
public Response getCategories();

I struggeled with this as well. In my case i used the swagger-maven-plugin. To solve this i added this within the maven plugin:
<securityDefinitions>
<securityDefinition>
<name>basicAuth</name>
<type>basic</type>
</securityDefinition>
</securityDefinitions>
After that i was able to add it on my resource like this:
#Api(value = "My REST Interface", authorizations = {#Authorization(value="basicAuth")})
The generated json included the security element for each endpoint:
"security":[{
"basicAuth" : []
}]
And the security definition:
"securityDefinitions" : {
"basicAuth" : {
"type" : "basic"
}
}
I hope this helps others as well.

You can use the #SwaggerDefinition
http://swagger.io/customizing-your-auto-generated-swagger-definitions-in-1-5-x/
or you can configure the swagger object directly, here's an example
http://www.programcreek.com/java-api-examples/index.php?source_dir=rakam-master/rakam/src/main/java/org/rakam/WebServiceRecipe.java

Related

OpenAPI, contract-first with Springdoc and multiple specs

I am trying to port a Swagger UI from Springfox to Springdoc.
The Swagger UI is generated via Maven plugin
<groupId>org.openapitools</groupId>
<artifactId>openapi-generator-maven-plugin</artifactId>
... from two different OpenAPI specifications, both implemented in the same Spring Boot application. We use two different specs for two different clients.
So far, my Swagger UI looked like this with Springfox. Note the drop-down list that allows to choose the spec to display.
Now, with Springdoc 1.6.6, the Swagger-UI looks like this.
Note that:
The default landing page is the sample Pet Store and none of my specifications, although I specified in my Spring Boot's application.yaml:
springdoc:
swagger-ui:
disable-swagger-default-url: true
No drop-down
I have to manually enter my specification's name into the "Explore" text field in order to see its Swagger UI
I tried addressing the missing drop-down by following I have installed OpenAPI 3 using springdoc, but the URL is strange. Can I change it to the expected value?, which claims to display a drop-down, but to no avail.
My questions:
How do I display the drop-down? Does Springdoc support it at all out-of-the-box?
Apparently, accessing http://localhost:8080/swagger-ui/index.html?urls.primaryName=Information makes the drop-down list of specs magically appear.
How do I make sure that the default URL http://localhost:8080/swagger-ui/index.html lands on one of my specs, and not on the Pet Store?
Here is btw. my Bean configuration:
#Configuration
public class SwaggerDocumentationConfig {
/**
* Path of the OpenAPI package extracted out of a random class in that package
*/
private static final String INFORMATION_PACKAGE = InformationApi.class.getPackageName();
/**
* Path of the OpenAPI package extracted out of a random class in that package
*/
private static final String OPERATIONS_PACKAGE = OperationsApi.class.getPackageName();
private GroupedOpenApi getBaseApiDoc(String groupName, String packagePath) {
return GroupedOpenApi.builder()
.group(groupName)
.packagesToScan(packagePath)
.build();
}
#Bean
public GroupedOpenApi getOperationsApiDoc() {
return getBaseApiDoc("Operations", OPERATIONS_PACKAGE);
}
#Bean
public GroupedOpenApi getInfoApiDoc() {
return getBaseApiDoc("Information", INFORMATION_PACKAGE);
}
#Bean
public OpenAPI springShopOpenAPI() {
return new OpenAPI()
.info(new Info().title("SpringShop API")
.description("Spring shop sample application")
.version("v0.0.1")
.license(new License().name("Apache 2.0").url("http://springdoc.org")))
.externalDocs(new ExternalDocumentation()
.description("SpringShop Wiki Documentation")
.url("https://springshop.wiki.github.org/docs"));
}}

Generate OpenAPI descriptions from JavaDoc

I have an application which provides an API with JAX-RS (Java API for RESTful Web Services / JSR-311).
For documentation purposes I provide an URL according to the OpenAPI-Specification, which is generated by Eclipse MicroProfile OpenAPI.
Everything is working fine, except the descriptions of the methods and parameters, which I need to add twice - in annotations and in JavaDoc:
/**
* Finds all resources with the given prefix.
*
* #param prefix
* the prefix of the resource
* #return the resources that start with the prefix
*/
#GET
#Path("/find/{prefix}")
#Produces(MediaType.APPLICATION_JSON)
#Operation(description = "Finds all resources with the given prefix")
public List<Resource> find(
#Parameter(description = "The prefix of the resource")
#PathParam("prefix") final String prefix) {
...
}
I know that no runtime library can read the JavaDoc (because it is not part of the class files), which is the main reason for the annotations. But I wonder if there is some other option for one of the OpenAPI generation tools (Swagger, Eclipse MicroProfile OpenAPI, ...), which prevents me from manually syncing the documentation?
In another project for example I'm using a doclet which serializes the JavaDoc and stores it in the class path, to present an Beans API documentation to the user at runtime. But even if I make use of this doclet here, I see no option to provide that JavaDoc descriptions to the OpenAPI libraries during runtime.
I know that I could drop the JavaDoc, if the users of my API use only "foreign languages", as they wouldn't see the JavaDoc anyway. But what happens if the other side of the API is a JAX-RS client? In that case the JavaDoc would be a huge support.
I got it running with Eclipse Microprofile OpenAPI.
I had to define my own OASFilter:
public class JavadocOASDescriptionFilter implements OASFilter {
#Override
public void filterOpenAPI(final OpenAPI openAPI) {
openAPI.getComponents().getSchemas().forEach(this::initializeSchema);
openAPI.getPaths().forEach(this::initializePathItem);
}
private void initializeSchema(final String name, final Schema schema) {
final SerializedJavadoc javadoc = findJavadocForSchema(name);
if (StringUtils.isEmpty(schema.getDescription())) {
schema.setDescription(javadoc.getTypeComment());
}
if (schema.getProperties() != null) {
schema.getProperties().forEach((property, propertySchema) -> {
if (StringUtils.isEmpty(propertySchema.getDescription())) {
propertySchema.setDescription(javadoc.getAttributeComments().get(property));
}
});
}
}
...
}
Then I had to declare that filter in META-INF/microprofile-config.properties:
mp.openapi.filter=mypackage.JavadocOASDescriptionReader
See here for the discussion on this topic: https://github.com/eclipse/microprofile-open-api/issues/485

Smallrye open api interceptor

I am developing a rest application.
Some endpoints require a custom header parameter, not related to authorisation. I created a custom annotation using jax-rs NameBinding. Here is an usage example:
#GET
#RequiresBankHeader
public int get(
#HeaderParam("bank")
#Parameter(ref = "#/components/parameters/banks")
String bank) {
return someService.getSomeInformation();
}
There is a provider that intercepts this call and do some routine using the information in the header parameter.
The problem is that I have to repeat '#HeaderParam("bank") #Parameter(ref = "#/components/parameters/banks") String bank' everywhere, just so it appears in Swagger, even though the service classes do not need it. I was able to at least reuse the parameter definition with ref = "#/components/parameters/banks", and declaring it in the OpenAPI.yml file, that Quarkus merges with generated code very nicely.
But I also want to create and interceptor to dynamically add this do the OpenApi definition whenever RequiresBankHeader annotation is present.
Is there a way to do it?
I dont think you can use interceptors to modify the generated Openapi schema output.
If all methods on a given endpoint require some parameter, you can specify it on class level like so:
#Path("/someendpoint")
public class MyEndpoint {
#HeaderParam("bank")
#Parameter(name = "bank")
String bank;
#GET
public Response getAll() {return Response.ok().build()}
#GET
#Path("{id}")
public Response someMethod(#PathParam("id") String id) {return Response.ok().build();}
}
As mentioned by Roberto Cortez, the MP OpenAPI spec provides a programmatic way to contribute metadata to the openapi.yml file.
It is not possible to detect an annotation in the JAX-RS endpoint definition, but it was good enough to automate what I needed. Since all methods that had the RequiresBankHeader return the same Schema, I was able to hack it like this:
public class OpenApiConfigurator implements OASFilter {
#Override
public Operation filterOperation(Operation operation) {
operation.getResponses().getAPIResponses().values().stream().
map(APIResponse::getContent).
filter(Objects::nonNull).
map(Content::getMediaTypes).
flatMap(mediaTypes -> mediaTypes.values().stream()).
map(MediaType::getSchema).
filter(Objects::nonNull).
map(Schema::getRef).
filter(Objects::nonNull).
filter(ref -> ref.contains("the common response schema")).
findAny().
ifPresent(schema -> {
ParameterImpl parameter = new ParameterImpl();
parameter.setRef("#/components/parameters/banks");
operation.addParameter(parameter);
});
return operation;
}
OpenApiConfigurator should be configure in the application properties, using mp.openapi.filter=com.yourcompany.OpenApiConfigurator

Using dynamic URL for Spring ReactiveFeignClient

I'm using ReactiveFeignClient from Playtika
I need to use dynamic URL especially for the host part because I want to use the same interface for several services that have the same request and response formats, but different host. The URLs on each service can have different host name and prefix, but all have the same suffix.
For example:
http://localhost:3001/games/purchase
http://localhost:3002/gadgets/phone/purchase
Actually I don't know whether it has the same behavior as non-reactive feign client. I follow the suggestion on How can I change the feign URL during the runtime?.
Here's the client interface.
#ReactiveFeignClient(
name = "dummy",
configuration = TransactionClient.Configuration.class
)
public interface TransactionClient {
// #PostMapping("/purchase") // Using #PostMapping and #RequestLine both don't work
#RequestLine("POST /purchase")
Mono<PurchaseResponseDto> doPurchase(
URI baseUrl,
#Valid #RequestBody PurchaseRequestDto requestDTO
);
#RequiredArgsConstructor
class Configuration {
#Bean
public ReactiveStatusHandler reactiveStatusHandler() {
return new CustomStatusHandler();
}
}
}
And here's the auto configuration
#Configuration
public class TransactionClientServiceAutoConfiguration {
#Bean
public Contract useFeignAnnotations() {
return new Contract.Default();
}
#Bean
#LoadBalanced
public TransactionClient botRemoteClient() {
return Feign.builder().target(Target.EmptyTarget.create(TransactionClient.class));
}
}
However, I got error indicating that no service with name dummy. It's just a dummy name indeed, because the name parameter is required for #ReactiveFeignClient annotation and I want to use the interface for multiple services.
How to make dynamic url possible for #ReactiveFeignClient
From reactive feign github I found this snippet:
IcecreamServiceApi client =
WebReactiveFeign //WebClient based reactive feign
.<IcecreamServiceApi>builder()
.target(IcecreamServiceApi.class, "http://www.myUrl.com")
You can change the url by creating a new instance of the client. Found no other way. Also, I added both #PostMapping and #RequestLine("POST") to the feign interface since I couldn't get the contracts option to work.
Sharing this for posterity or until a better version comes along.

How to use swagger with OAuth API?

Is it possible to use swagger as a documentation/testing tool for APIs that use OAuth2? I don't see anything on the swagger site (or anywhere else for that matter). Every usage I've seen uses either an API key, HTTP basic, or cookies.
I have been working along the same lines. Swagger will accept any header or URL defined api key or token. Adding a validation helper to the api and app is a standard approach.
Oauth does require a HTML review and or login to start the handshake aouth process. This means that a swagger api will need to support a web interface for a standard login and scope acceptance. Rolling oauth into swagger results in a few logic loops, which long term are not easy to support.
A different approach we are exploring is the option to let the api handle and store access tokens for a number of different oauth providers; GitHub, twitter and Facebook. This might result in login loops as well.
late to the party here but oAuth support is now in 1.3.0-RC1 of swagger-core. The javascript library which can support oAuth was released yesterday in swagger-js. Finally, the swagger-ui is in develop phase, and will soon have a oAuth implicit and server flow.
the blog´s post http://developers-blog.helloreverb.com/enabling-oauth-with-swagger/ cited by #fehguy shows an example of java code to include the authorization data in json generated by swagger, however my question was where it should be included with app with Spring, JAXRS and CXF. I didn´t find it in CXF + JAXRS Sample :https://github.com/swagger-api/swagger-core/tree/master/samples/java-jaxrs-cxf
However, looking for a bit more and gotcha !
https://github.com/swagger-api/swagger-core/blob/master/samples/java-jersey-spring/src/main/resources/beans-asset-ws.xml
Is necessary include a Bean with a class called Bootstrap (extends HttpServlet) and a static block !
Opinion: Maybe it would be more “spring-friendly” loaded from annotations by SwaggerConfig Scanner in Rest class instead a static block in a servlet.
#Configuration
public class SwaggerConfiguration {
#Bean
#DependsOn("jaxRsServer") //org.apache.cxf.endpoint.Server bean
public ServletContextInitializer initializer() {
return new ServletContextInitializer() {
#Override
public void onStartup(ServletContext servletContext) throws ServletException {
BeanConfig scanner = (BeanConfig) ScannerFactory.getScanner();
Swagger swagger = scanner.getSwagger();
servletContext.setAttribute("swagger", swagger);
}
};
}
#Bean
public Feature swaggerFeature() {
XSwagger2Feature feature = new XSwagger2Feature();
return feature;
}
#Bean
public FilterRegistrationBean swaggerApiFilter() {
ApiOriginFilter filter = new ApiOriginFilter();
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(filter);
registrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return registrationBean;
}
public static class XSwagger2Feature extends Swagger2Feature {
#Override
protected void addSwaggerResource(Server server) {
super.addSwaggerResource(server);
BeanConfig scanner = (BeanConfig) ScannerFactory.getScanner();
Swagger swagger = scanner.getSwagger();
swagger.securityDefinition("api_key", new ApiKeyAuthDefinition("api_key", In.HEADER));
swagger.securityDefinition("petstore_auth",
new OAuth2Definition()
.implicit("http://petstore.swagger.io/api/oauth/dialog")
.scope("read:pets", "read your pets")
.scope("write:pets", "modify pets in your account"));
}
}
}
IOdocs from mashery seems to support OAuth, but it's quite different from swagger (redis, node, etc.). It's available on github.

Resources