This is an automated email from the ASF dual-hosted git repository. davsclaus pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/camel.git
commit a459ecd029f9e4f1481a3c6940cdde3a781f4e06 Author: Claus Ibsen <claus.ib...@gmail.com> AuthorDate: Sun Jun 17 10:33:16 2018 +0200 CAMEL-9751: Allow to configure swagger security requirements in generated swagger api docs in rest-dsl. --- .../apache/camel/model/rest/RestDefinition.java | 24 ++++++++ .../camel/model/rest/SecurityDefinition.java | 58 ++++++++++++++++++ .../apache/camel/model/rest/VerbDefinition.java | 14 +++++ .../org/apache/camel/model/rest/jaxb.index | 1 + .../apache/camel/component/rest/RestRefTest.xml | 1 + .../src/main/docs/swagger-java.adoc | 50 +++++++++++++--- .../apache/camel/swagger/RestSwaggerReader.java | 70 ++++++++++++++-------- .../RestSwaggerReaderModelApiSecurityTest.java | 7 +++ 8 files changed, 191 insertions(+), 34 deletions(-) diff --git a/camel-core/src/main/java/org/apache/camel/model/rest/RestDefinition.java b/camel-core/src/main/java/org/apache/camel/model/rest/RestDefinition.java index 5583def..ff8866d 100644 --- a/camel-core/src/main/java/org/apache/camel/model/rest/RestDefinition.java +++ b/camel-core/src/main/java/org/apache/camel/model/rest/RestDefinition.java @@ -573,6 +573,30 @@ public class RestDefinition extends OptionalIdentifiedDefinition<RestDefinition> } /** + * Sets the security setting for this verb. + */ + public RestDefinition security(String key) { + return security(key, null); + } + + /** + * Sets the security setting for this verb. + */ + public RestDefinition security(String key, String scopes) { + // add to last verb + if (getVerbs().isEmpty()) { + throw new IllegalArgumentException("Must add verb first, such as get/post/delete"); + } + + VerbDefinition verb = getVerbs().get(getVerbs().size() - 1); + SecurityDefinition sd = new SecurityDefinition(); + sd.setKey(key); + sd.setScopes(scopes); + verb.getSecurity().add(sd); + return this; + } + + /** * Routes directly to the given static endpoint. * <p/> * If you need additional routing capabilities, then use {@link #route()} instead. diff --git a/camel-core/src/main/java/org/apache/camel/model/rest/SecurityDefinition.java b/camel-core/src/main/java/org/apache/camel/model/rest/SecurityDefinition.java new file mode 100644 index 0000000..52ea20d --- /dev/null +++ b/camel-core/src/main/java/org/apache/camel/model/rest/SecurityDefinition.java @@ -0,0 +1,58 @@ +/** + * 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 + * <p> + * http://www.apache.org/licenses/LICENSE-2.0 + * <p> + * 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. + */ +package org.apache.camel.model.rest; + +import javax.xml.bind.annotation.XmlAccessType; +import javax.xml.bind.annotation.XmlAccessorType; +import javax.xml.bind.annotation.XmlAttribute; +import javax.xml.bind.annotation.XmlRootElement; + +import org.apache.camel.spi.Metadata; + +@Metadata(label = "rest,security", title = "Security") +@XmlRootElement(name = "security") +@XmlAccessorType(XmlAccessType.FIELD) +public class SecurityDefinition { + + @XmlAttribute(required = true) @Metadata(required = "true") + private String key; + + @XmlAttribute + private String scopes; + + public String getKey() { + return key; + } + + /** + * Key used to refer to this security definition + */ + public void setKey(String key) { + this.key = key; + } + + public String getScopes() { + return scopes; + } + + /** + * The scopes to allow (separate multiple scopes by comma) + */ + public void setScopes(String scopes) { + this.scopes = scopes; + } +} diff --git a/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java b/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java index fbc2055..27ad9fd 100644 --- a/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java +++ b/camel-core/src/main/java/org/apache/camel/model/rest/VerbDefinition.java @@ -52,6 +52,9 @@ public class VerbDefinition extends OptionalIdentifiedDefinition<VerbDefinition> @XmlElementRef private List<RestOperationResponseMsgDefinition> responseMsgs = new ArrayList<>(); + @XmlElementRef + private List<SecurityDefinition> security = new ArrayList<>(); + @XmlAttribute private String uri; @@ -138,6 +141,17 @@ public class VerbDefinition extends OptionalIdentifiedDefinition<VerbDefinition> this.responseMsgs = responseMsgs; } + public List<SecurityDefinition> getSecurity() { + return security; + } + + /** + * Sets the swagger security settings for this verb. + */ + public void setSecurity(List<SecurityDefinition> security) { + this.security = security; + } + public String getMethod() { return method; } diff --git a/camel-core/src/main/resources/org/apache/camel/model/rest/jaxb.index b/camel-core/src/main/resources/org/apache/camel/model/rest/jaxb.index index e032df8..a9c8a6a 100644 --- a/camel-core/src/main/resources/org/apache/camel/model/rest/jaxb.index +++ b/camel-core/src/main/resources/org/apache/camel/model/rest/jaxb.index @@ -37,4 +37,5 @@ RestSecurityApiKey RestSecurityBasicAuth RestSecuritiesDefinition RestSecurityOAuth2 +SecurityDefinition VerbDefinition diff --git a/components/camel-spring/src/test/resources/org/apache/camel/component/rest/RestRefTest.xml b/components/camel-spring/src/test/resources/org/apache/camel/component/rest/RestRefTest.xml index c53d943..732c73f 100644 --- a/components/camel-spring/src/test/resources/org/apache/camel/component/rest/RestRefTest.xml +++ b/components/camel-spring/src/test/resources/org/apache/camel/component/rest/RestRefTest.xml @@ -31,6 +31,7 @@ <rest path="/say/hello"> <get> <to uri="direct:hello"/> + <security key="ausss" scopes="write:pets,read:pets"/> </get> </rest> </restContext> diff --git a/components/camel-swagger-java/src/main/docs/swagger-java.adoc b/components/camel-swagger-java/src/main/docs/swagger-java.adoc index 0983f5d..02dbe61 100644 --- a/components/camel-swagger-java/src/main/docs/swagger-java.adoc +++ b/components/camel-swagger-java/src/main/docs/swagger-java.adoc @@ -9,9 +9,6 @@ services and their APIs using http://swagger.io/[Swagger]. Maven users will need to add the following dependency to their `pom.xml` for this component: -From *Camel 2.16* onwards the swagger component is purely Java based, -and its - [source,xml] ---- <dependency> @@ -25,9 +22,6 @@ and its The camel-swagger-java module can be used from the REST components (without the need for servlet) -For an example see the `camel-example-swagger-cdi` in the examples -directory of the Apache Camel distribution. - === Using Swagger in rest-dsl @@ -82,8 +76,7 @@ with `api.xxx` is configured using `apiProperty` dsl. |cors |Boolean |Whether to enable CORS. Notice this only enables CORS for the api browser, and not the actual access to the REST services. Is default -false. Instead of using this option is recommended to use the CorsFilte, see -further below. +false. |swagger.version |String |Swagger spec version. Is default 2.0. @@ -138,6 +131,47 @@ wildcard. Its the same pattern matching as used by Intercept |=== +=== Adding Security Definitions in API doc + +*Available as of Camel 2.22.0* + +The Rest DSL now supports declaring Swagger `securityDefinitions` in the generated API document. +For example as shown below: + +[source,java] +---- +rest("/user").tag("dude").description("User rest service") + // setup security definitions + .securityDefinitions() + .oauth2("petstore_auth").authorizationUrl("http://petstore.swagger.io/oauth/dialog").end() + .apiKey("api_key").withHeader("myHeader").end() + .end() + .consumes("application/json").produces("application/json") +---- + +Here we have setup two security definitions + +- OAuth2 - with implicit authorization with the provided url +- Api Key - using an api key that comes from HTTP header named _myHeader_ + +Then you need to specify on the rest operations which security to use by referring to +their key (petstore_auth or api_key). + +[source,java] +---- +.get("/{id}/{date}").description("Find user by id and date").outType(User.class) + .security("api_key") + +... + +.put().description("Updates or create a user").type(User.class) + .security("petstore_auth", "write:pets,read:pets") +---- + +Here the get operation is using the Api Key security and the put operation +is using OAuth security with permitted scopes of read and write pets. + + === ContextIdListing enabled diff --git a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerReader.java b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerReader.java index c100ae8..128ea21 100644 --- a/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerReader.java +++ b/components/camel-swagger-java/src/main/java/org/apache/camel/swagger/RestSwaggerReader.java @@ -21,6 +21,7 @@ import java.lang.invoke.MethodType; import java.util.ArrayList; import java.util.Collections; import java.util.Comparator; +import java.util.Iterator; import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; @@ -39,6 +40,7 @@ import io.swagger.models.Operation; import io.swagger.models.Path; import io.swagger.models.RefModel; import io.swagger.models.Response; +import io.swagger.models.SecurityRequirement; import io.swagger.models.Swagger; import io.swagger.models.Tag; import io.swagger.models.auth.ApiKeyAuthDefinition; @@ -74,6 +76,7 @@ import org.apache.camel.model.rest.RestSecurityApiKey; import org.apache.camel.model.rest.RestSecurityBasicAuth; import org.apache.camel.model.rest.RestSecurityDefinition; import org.apache.camel.model.rest.RestSecurityOAuth2; +import org.apache.camel.model.rest.SecurityDefinition; import org.apache.camel.model.rest.VerbDefinition; import org.apache.camel.spi.ClassResolver; import org.apache.camel.util.FileUtil; @@ -134,33 +137,35 @@ public class RestSwaggerReader { // setup security definitions RestSecuritiesDefinition sd = rest.getSecurityDefinitions(); - for (RestSecurityDefinition def : sd.getSecurityDefinitions()) { - if (def instanceof RestSecurityBasicAuth) { - BasicAuthDefinition auth = new BasicAuthDefinition(); - auth.setDescription(def.getDescription()); - swagger.addSecurityDefinition(def.getKey(), auth); - } else if (def instanceof RestSecurityApiKey) { - RestSecurityApiKey rs = (RestSecurityApiKey) def; - ApiKeyAuthDefinition auth = new ApiKeyAuthDefinition(); - auth.setDescription(rs.getDescription()); - auth.setName(rs.getName()); - if (rs.getInHeader() != null && rs.getInHeader()) { - auth.setIn(In.HEADER); - } else { - auth.setIn(In.QUERY); - } - swagger.addSecurityDefinition(def.getKey(), auth); - } else if (def instanceof RestSecurityOAuth2) { - RestSecurityOAuth2 rs = (RestSecurityOAuth2) def; - OAuth2Definition auth = new OAuth2Definition(); - auth.setDescription(rs.getDescription()); - auth.setFlow(rs.getFlow()); - auth.setAuthorizationUrl(rs.getAuthorizationUrl()); - auth.setTokenUrl(rs.getTokenUrl()); - for (RestPropertyDefinition scope : rs.getScopes()) { - auth.addScope(scope.getKey(), scope.getValue()); + if (sd != null) { + for (RestSecurityDefinition def : sd.getSecurityDefinitions()) { + if (def instanceof RestSecurityBasicAuth) { + BasicAuthDefinition auth = new BasicAuthDefinition(); + auth.setDescription(def.getDescription()); + swagger.addSecurityDefinition(def.getKey(), auth); + } else if (def instanceof RestSecurityApiKey) { + RestSecurityApiKey rs = (RestSecurityApiKey) def; + ApiKeyAuthDefinition auth = new ApiKeyAuthDefinition(); + auth.setDescription(rs.getDescription()); + auth.setName(rs.getName()); + if (rs.getInHeader() != null && rs.getInHeader()) { + auth.setIn(In.HEADER); + } else { + auth.setIn(In.QUERY); + } + swagger.addSecurityDefinition(def.getKey(), auth); + } else if (def instanceof RestSecurityOAuth2) { + RestSecurityOAuth2 rs = (RestSecurityOAuth2) def; + OAuth2Definition auth = new OAuth2Definition(); + auth.setDescription(rs.getDescription()); + auth.setFlow(rs.getFlow()); + auth.setAuthorizationUrl(rs.getAuthorizationUrl()); + auth.setTokenUrl(rs.getTokenUrl()); + for (RestPropertyDefinition scope : rs.getScopes()) { + auth.addScope(scope.getKey(), scope.getValue()); + } + swagger.addSecurityDefinition(def.getKey(), auth); } - swagger.addSecurityDefinition(def.getKey(), auth); } } @@ -281,6 +286,19 @@ public class RestSwaggerReader { op.summary(verb.getDescriptionText()); } + // security + for (SecurityDefinition sd : verb.getSecurity()) { + List<String> scopes = new ArrayList<>(); + if (sd.getScopes() != null) { + Iterator<Object> it = ObjectHelper.createIterator(sd.getScopes()); + while (it.hasNext()) { + String scope = it.next().toString(); + scopes.add(scope); + } + } + op.addSecurity(sd.getKey(), scopes); + } + for (RestOperationParamDefinition param : verb.getParams()) { Parameter parameter = null; if (param.getType().equals(RestParamType.body)) { diff --git a/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/RestSwaggerReaderModelApiSecurityTest.java b/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/RestSwaggerReaderModelApiSecurityTest.java index dcebc21..c8708d2 100644 --- a/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/RestSwaggerReaderModelApiSecurityTest.java +++ b/components/camel-swagger-java/src/test/java/org/apache/camel/swagger/RestSwaggerReaderModelApiSecurityTest.java @@ -52,11 +52,15 @@ public class RestSwaggerReaderModelApiSecurityTest extends CamelTestSupport { .get("/{id}/{date}").description("Find user by id and date").outType(User.class) .responseMessage().message("The user returned").endResponseMessage() + // setup security for this rest verb + .security("api_key") .param().name("id").type(RestParamType.path).description("The id of the user to get").endParam() .param().name("date").type(RestParamType.path).description("The date").dataFormat("date").endParam() .to("bean:userService?method=getUser(${header.id})") .put().description("Updates or create a user").type(User.class) + // setup security for this rest verb + .security("petstore_auth", "write:pets,read:pets") .param().name("body").type(RestParamType.body).description("The user to update or create").endParam() .to("bean:userService?method=updateUser") @@ -94,6 +98,9 @@ public class RestSwaggerReaderModelApiSecurityTest extends CamelTestSupport { assertTrue(json.contains("\"type\" : \"apiKey\",")); assertTrue(json.contains("\"in\" : \"header\"")); assertTrue(json.contains("\"host\" : \"localhost:8080\"")); + assertTrue(json.contains("\"security\" : [ {")); + assertTrue(json.contains("\"petstore_auth\" : [ \"write:pets\", \"read:pets\" ]")); + assertTrue(json.contains("\"api_key\" : [ ]")); assertTrue(json.contains("\"description\" : \"The user returned\"")); assertTrue(json.contains("\"$ref\" : \"#/definitions/User\"")); assertTrue(json.contains("\"x-className\"")); -- To stop receiving notification emails like this one, please contact davscl...@apache.org.