Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,20 @@

import java.lang.reflect.Type;
import java.util.Arrays;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import javax.annotation.Nonnull;

import org.apache.commons.lang3.StringUtils;
import org.apache.servicecomb.swagger.SwaggerUtils;
import org.apache.servicecomb.swagger.generator.ClassAnnotationProcessor;
import org.apache.servicecomb.swagger.generator.SwaggerGenerator;

import io.swagger.annotations.Scope;
import io.swagger.annotations.SecurityDefinition;
import io.swagger.annotations.SwaggerDefinition;
import io.swagger.models.Contact;
import io.swagger.models.ExternalDocs;
Expand All @@ -36,6 +41,11 @@
import io.swagger.models.Scheme;
import io.swagger.models.Swagger;
import io.swagger.models.Tag;
import io.swagger.models.auth.ApiKeyAuthDefinition;
import io.swagger.models.auth.BasicAuthDefinition;
import io.swagger.models.auth.In;
import io.swagger.models.auth.OAuth2Definition;
import io.swagger.models.auth.SecuritySchemeDefinition;
import io.swagger.util.BaseReaderUtils;

public class SwaggerDefinitionProcessor implements ClassAnnotationProcessor<SwaggerDefinition> {
Expand All @@ -57,15 +67,16 @@ public void process(SwaggerGenerator swaggerGenerator, SwaggerDefinition definit

SwaggerUtils.setConsumes(swagger, definitionAnnotation.consumes());
SwaggerUtils.setProduces(swagger, definitionAnnotation.produces());
convertSchemes(definitionAnnotation, swagger);
convertTags(definitionAnnotation, swagger);
convertInfo(definitionAnnotation.info(), swagger);
swagger.setSchemes(convertSchemes(definitionAnnotation.schemes()));
swagger.setTags(convertTags(definitionAnnotation.tags()));
swagger.setSecurityDefinitions(convertSecurityDefinitions(definitionAnnotation.securityDefinition()));
swagger.setInfo(convertInfo(definitionAnnotation.info()));
swagger.setExternalDocs(convertExternalDocs(definitionAnnotation.externalDocs()));
}

private void convertInfo(io.swagger.annotations.Info infoAnnotation, Swagger swagger) {
private Info convertInfo(io.swagger.annotations.Info infoAnnotation) {
if (infoAnnotation == null) {
return;
return null;
}

Info info = new Info();
Expand All @@ -82,7 +93,7 @@ private void convertInfo(io.swagger.annotations.Info infoAnnotation, Swagger swa
info.setLicense(convertLicense(infoAnnotation.license()));
info.getVendorExtensions().putAll(BaseReaderUtils.parseExtensions(infoAnnotation.extensions()));

swagger.setInfo(info);
return info;
}

private License convertLicense(io.swagger.annotations.License licenseAnnotation) {
Expand Down Expand Up @@ -124,21 +135,16 @@ private Contact convertContact(io.swagger.annotations.Contact contactAnnotation)
return contact;
}

private void convertTags(SwaggerDefinition definitionAnnotation, Swagger swagger) {
if (definitionAnnotation.tags() == null) {
return;
private List<Tag> convertTags(io.swagger.annotations.Tag[] tagArray) {
if (tagArray == null) {
return null;
}

Stream<io.swagger.annotations.Tag> stream =
Arrays.asList(definitionAnnotation.tags()).stream();
List<Tag> tags = stream
List<Tag> tags = Arrays.stream(tagArray)
.filter(t -> !t.name().isEmpty())
.map(this::convertTag)
.collect(Collectors.toList());
if (tags.isEmpty()) {
return;
}
swagger.setTags(tags);
return tags.isEmpty() ? null : tags;
}

private Tag convertTag(io.swagger.annotations.Tag tagAnnotation) {
Expand Down Expand Up @@ -167,15 +173,14 @@ private ExternalDocs convertExternalDocs(io.swagger.annotations.ExternalDocs ann
return externalDocs;
}

private void convertSchemes(SwaggerDefinition definitionAnnotation, Swagger swagger) {
if (definitionAnnotation.schemes() == null) {
return;
private List<Scheme> convertSchemes(SwaggerDefinition.Scheme[] schemeArray) {
if (schemeArray == null) {
return null;
}

Stream<io.swagger.annotations.SwaggerDefinition.Scheme> stream =
Arrays.asList(definitionAnnotation.schemes()).stream();
List<Scheme> schemes = stream.map(this::convertScheme).collect(Collectors.toList());
swagger.setSchemes(schemes);
return Arrays.stream(schemeArray)
.map(this::convertScheme)
.collect(Collectors.toList());
}

private Scheme convertScheme(io.swagger.annotations.SwaggerDefinition.Scheme annotationScheme) {
Expand All @@ -184,4 +189,80 @@ private Scheme convertScheme(io.swagger.annotations.SwaggerDefinition.Scheme ann
}
return Scheme.forValue(annotationScheme.name());
}

private Map<String, SecuritySchemeDefinition> convertSecurityDefinitions(
SecurityDefinition securityDefinition) {
Map<String, SecuritySchemeDefinition> definitionMap = new LinkedHashMap<>();

Arrays.stream(securityDefinition.oAuth2Definitions())
.forEach(annotation -> addSecurityDefinition(definitionMap, annotation.key(), convertOAuth2(annotation)));
Arrays.stream(securityDefinition.apiKeyAuthDefinitions())
.forEach(annotation -> addSecurityDefinition(definitionMap, annotation.key(), convertApiKey(annotation)));
Arrays.stream(securityDefinition.basicAuthDefinitions())
.forEach(annotation -> addSecurityDefinition(definitionMap, annotation.key(), convertBasicAuth(annotation)));

return definitionMap.isEmpty() ? null : definitionMap;
}

private void addSecurityDefinition(Map<String, SecuritySchemeDefinition> definitionMap,
String key, SecuritySchemeDefinition definition) {
if (StringUtils.isEmpty(key) || definition == null) {
return;
}

definitionMap.put(key, definition);
}

private String emptyAsNull(@Nonnull String value) {
return value.isEmpty() ? null : value;
}

private OAuth2Definition convertOAuth2(io.swagger.annotations.OAuth2Definition annotation) {
OAuth2Definition definition = new OAuth2Definition();

definition.setDescription(emptyAsNull(annotation.description()));
definition.setFlow(emptyAsNull(annotation.flow().name()));
definition.setAuthorizationUrl(emptyAsNull(annotation.authorizationUrl()));
definition.setTokenUrl(emptyAsNull(annotation.tokenUrl()));
for (Scope scope : annotation.scopes()) {
if (StringUtils.isEmpty(scope.name())) {
continue;
}
definition.addScope(scope.name(), scope.description());
}

if (definition.getDescription() == null
&& definition.getFlow() == null
&& definition.getAuthorizationUrl() == null
&& definition.getTokenUrl() == null
&& definition.getScopes() == null) {
return null;
}

return definition;
}

private SecuritySchemeDefinition convertApiKey(io.swagger.annotations.ApiKeyAuthDefinition annotation) {
if (StringUtils.isEmpty(annotation.name())) {
return null;
}

ApiKeyAuthDefinition definition = new ApiKeyAuthDefinition();

definition.setDescription(emptyAsNull(annotation.description()));
definition.setIn(In.forValue(annotation.in().name()));
definition.setName(annotation.name());

return definition;
}

private SecuritySchemeDefinition convertBasicAuth(io.swagger.annotations.BasicAuthDefinition annotation) {
if (annotation.description().isEmpty()) {
return null;
}

BasicAuthDefinition definition = new BasicAuthDefinition();
definition.setDescription(annotation.description());
return definition;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,10 +29,17 @@
import org.junit.Test;

import io.swagger.annotations.Api;
import io.swagger.annotations.ApiKeyAuthDefinition;
import io.swagger.annotations.ApiKeyAuthDefinition.ApiKeyLocation;
import io.swagger.annotations.BasicAuthDefinition;
import io.swagger.annotations.Contact;
import io.swagger.annotations.ExternalDocs;
import io.swagger.annotations.Info;
import io.swagger.annotations.License;
import io.swagger.annotations.OAuth2Definition;
import io.swagger.annotations.OAuth2Definition.Flow;
import io.swagger.annotations.Scope;
import io.swagger.annotations.SecurityDefinition;
import io.swagger.annotations.SwaggerDefinition;
import io.swagger.annotations.SwaggerDefinition.Scheme;
import io.swagger.annotations.Tag;
Expand Down Expand Up @@ -61,6 +68,46 @@ private class SwaggerTestTarget_EmptyMediaType {
private class EmptySwaggerDefinition {
}

@SwaggerDefinition(securityDefinition = @SecurityDefinition(
oAuth2Definitions = {
@OAuth2Definition(key = "", flow = Flow.IMPLICIT),
@OAuth2Definition(key = "oauth2-only-flow", flow = Flow.IMPLICIT),
@OAuth2Definition(key = "oauth2-desc", description = "desc", flow = Flow.PASSWORD),
@OAuth2Definition(key = "oauth2-authorizationUrl", authorizationUrl = "url", flow = Flow.PASSWORD),
@OAuth2Definition(key = "oauth2-tokenUrl", tokenUrl = "url", flow = Flow.PASSWORD),
@OAuth2Definition(key = "oauth2-scope", flow = Flow.PASSWORD,
scopes = {
@Scope(name = "", description = ""),
@Scope(name = "", description = "desc"),
@Scope(name = "scope-1", description = ""),
@Scope(name = "scope-2", description = "desc")
}),
})
)
private class SecurityOAuth2 {
}

@SwaggerDefinition(securityDefinition = @SecurityDefinition(
apiKeyAuthDefinitions = {
@ApiKeyAuthDefinition(key = "", in = ApiKeyLocation.HEADER, name = "h1"),
@ApiKeyAuthDefinition(key = "apikey-no-name", in = ApiKeyLocation.QUERY, name = ""),
@ApiKeyAuthDefinition(key = "apikey-no-desc", in = ApiKeyLocation.QUERY, name = "q1"),
@ApiKeyAuthDefinition(key = "apikey-desc", description = "desc", in = ApiKeyLocation.QUERY, name = "q2")
}
))
private class SecurityApiKey {
}

@SwaggerDefinition(securityDefinition = @SecurityDefinition(
basicAuthDefinitions = {
@BasicAuthDefinition(key = ""),
@BasicAuthDefinition(key = "basic-no-desc"),
@BasicAuthDefinition(key = "basic-desc", description = "desc")
}
))
private class SecurityBasic {
}

@Test
public void testProcess() {
Swagger swagger = SwaggerGenerator.generate(SwaggerTestTarget.class);
Expand Down Expand Up @@ -94,4 +141,19 @@ public void testProcess_emptyMediaType() {
public void emptySwaggerDefinitionMediaType() {
UnitTestSwaggerUtils.testSwagger("schemas/emptySwaggerDefinition.yaml", EmptySwaggerDefinition.class);
}

@Test
public void should_process_security_oauth2() {
UnitTestSwaggerUtils.testSwagger("schemas/security-oauth2.yaml", SecurityOAuth2.class);
}

@Test
public void should_process_security_apikey() {
UnitTestSwaggerUtils.testSwagger("schemas/security-apikey.yaml", SecurityApiKey.class);
}

@Test
public void should_process_security_basic() {
UnitTestSwaggerUtils.testSwagger("schemas/security-basic.yaml", SecurityBasic.class);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
## ---------------------------------------------------------------------------
## Licensed to the Apache Software Foundation (ASF) under one or more
## contributor license agreements. See the NOTICE file distributed with
## this work for additional information regarding copyright ownership.
## The ASF licenses this file to You under the Apache License, Version 2.0
## (the "License"); you may not use this file except in compliance with
## the License. You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
## ---------------------------------------------------------------------------

---
swagger: "2.0"
info:
version: "1.0.0"
title: "swagger definition for org.apache.servicecomb.swagger.generator.core.processor.annotation.SwaggerDefinitionProcessorTest$SecurityApiKey"
x-java-interface: "gen.cse.ms.ut.SecurityApiKeyIntf"
basePath: "/SecurityApiKey"
schemes:
- "http"
consumes:
- "application/json"
produces:
- "application/json"
securityDefinitions:
apikey-no-desc:
type: "apiKey"
name: "q1"
in: "query"
apikey-desc:
description: "desc"
type: "apiKey"
name: "q2"
in: "query"
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
## ---------------------------------------------------------------------------
## Licensed to the Apache Software Foundation (ASF) under one or more
## contributor license agreements. See the NOTICE file distributed with
## this work for additional information regarding copyright ownership.
## The ASF licenses this file to You under the Apache License, Version 2.0
## (the "License"); you may not use this file except in compliance with
## the License. You may obtain a copy of the License at
##
## http://www.apache.org/licenses/LICENSE-2.0
##
## Unless required by applicable law or agreed to in writing, software
## distributed under the License is distributed on an "AS IS" BASIS,
## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
## See the License for the specific language governing permissions and
## limitations under the License.
## ---------------------------------------------------------------------------

---
swagger: "2.0"
info:
version: "1.0.0"
title: "swagger definition for org.apache.servicecomb.swagger.generator.core.processor.annotation.SwaggerDefinitionProcessorTest$SecurityBasic"
x-java-interface: "gen.cse.ms.ut.SecurityBasicIntf"
basePath: "/SecurityBasic"
schemes:
- "http"
consumes:
- "application/json"
produces:
- "application/json"
securityDefinitions:
basic-desc:
description: "desc"
type: "basic"
Loading