This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/main by this push:
new 43dd6efbd0b CAMEL-21164: camel-rest - Code first should use actual
values for property placeholders in dumped API spec (#15460)
43dd6efbd0b is described below
commit 43dd6efbd0bd03a9ec6e8642a936a42ac5f2ebc3
Author: avi5kdonrh <[email protected]>
AuthorDate: Sat Sep 7 11:38:57 2024 +0530
CAMEL-21164: camel-rest - Code first should use actual values for property
placeholders in dumped API spec (#15460)
Changes: camel-openapi-java:
org.apache.camel.openapi RestOpenApiReader
org.apache.camel.openapi.SpringRestOpenApiReaderModelApiSecurityPlaceholderTest
org/apache/camel/openapi/SpringRestOpenApiReaderModelApiSecurityPlaceholderTest.xml
---
.../apache/camel/openapi/RestOpenApiReader.java | 63 ++++-----
...enApiReaderModelApiSecurityPlaceholderTest.java | 145 +++++++++++++++++++++
...penApiReaderModelApiSecurityPlaceholderTest.xml | 93 +++++++++++++
3 files changed, 272 insertions(+), 29 deletions(-)
diff --git
a/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestOpenApiReader.java
b/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestOpenApiReader.java
index c5672440745..d50cb171c60 100644
---
a/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestOpenApiReader.java
+++
b/components/camel-openapi-java/src/main/java/org/apache/camel/openapi/RestOpenApiReader.java
@@ -272,7 +272,7 @@ public class RestOpenApiReader {
? new String[] { getValue(camelContext,
rest.getPath()) }
: new String[0];
- parseOas30(openApi, rest, pathAsTags);
+ parseOas30(camelContext, openApi, rest, pathAsTags);
// gather all types in use
Set<String> types = new LinkedHashSet<>();
@@ -341,7 +341,7 @@ public class RestOpenApiReader {
});
}
- private void parseOas30(OpenAPI openApi, RestDefinition rest, String[]
pathAsTags) {
+ private void parseOas30(CamelContext camelContext, OpenAPI openApi,
RestDefinition rest, String[] pathAsTags) {
String summary = rest.getDescriptionText();
for (String tag : pathAsTags) {
@@ -358,36 +358,37 @@ public class RestOpenApiReader {
for (RestSecurityDefinition def : sd.getSecurityDefinitions()) {
if (def instanceof BasicAuthDefinition) {
SecurityScheme auth = new
SecurityScheme().type(SecurityScheme.Type.HTTP)
- .scheme("basic").description(def.getDescription());
- openApi.getComponents().addSecuritySchemes(def.getKey(),
auth);
+
.scheme("basic").description(CamelContextHelper.parseText(camelContext,
def.getDescription()));
+
openApi.getComponents().addSecuritySchemes(CamelContextHelper.parseText(camelContext,
def.getKey()), auth);
} else if (def instanceof BearerTokenDefinition) {
SecurityScheme auth = new
SecurityScheme().type(SecurityScheme.Type.HTTP)
- .scheme("bearer").description(def.getDescription())
- .bearerFormat(((BearerTokenDefinition)
def).getFormat());
- openApi.getComponents().addSecuritySchemes(def.getKey(),
auth);
+
.scheme("bearer").description(CamelContextHelper.parseText(camelContext,
def.getDescription()))
+ .bearerFormat(
+
(CamelContextHelper.parseText(camelContext, ((BearerTokenDefinition)
def).getFormat())));
+
openApi.getComponents().addSecuritySchemes(CamelContextHelper.parseText(camelContext,
def.getKey()), auth);
} else if (def instanceof ApiKeyDefinition) {
ApiKeyDefinition rs = (ApiKeyDefinition) def;
SecurityScheme auth = new
SecurityScheme().type(SecurityScheme.Type.APIKEY)
-
.name(rs.getName()).description(def.getDescription());
-
- if (rs.getInHeader() != null &&
Boolean.parseBoolean(rs.getInHeader())) {
+ .name(CamelContextHelper.parseText(camelContext,
rs.getName()))
+
.description(CamelContextHelper.parseText(camelContext, def.getDescription()));
+ if
(Boolean.TRUE.equals(CamelContextHelper.parseBoolean(camelContext,
rs.getInHeader()))) {
auth.setIn(SecurityScheme.In.HEADER);
- } else if (rs.getInQuery() != null &&
Boolean.parseBoolean(rs.getInQuery())) {
+ } else if
(Boolean.TRUE.equals(CamelContextHelper.parseBoolean(camelContext,
rs.getInQuery()))) {
auth.setIn(SecurityScheme.In.QUERY);
- } else if (rs.getInCookie() != null &&
Boolean.parseBoolean(rs.getInCookie())) {
+ } else if
(Boolean.TRUE.equals(CamelContextHelper.parseBoolean(camelContext,
rs.getInCookie()))) {
auth.setIn(SecurityScheme.In.COOKIE);
} else {
throw new IllegalStateException("No API Key location
specified.");
}
- openApi.getComponents().addSecuritySchemes(def.getKey(),
auth);
+
openApi.getComponents().addSecuritySchemes(CamelContextHelper.parseText(camelContext,
def.getKey()), auth);
} else if (def instanceof OAuth2Definition) {
OAuth2Definition rs = (OAuth2Definition) def;
SecurityScheme auth = new
SecurityScheme().type(SecurityScheme.Type.OAUTH2)
- .description(def.getDescription());
- String flow = rs.getFlow();
+
.description(CamelContextHelper.parseText(camelContext, def.getDescription()));
+ String flow = CamelContextHelper.parseText(camelContext,
rs.getFlow());
if (flow == null) {
- flow = inferOauthFlow(rs);
+ flow = inferOauthFlow(camelContext, rs);
}
OAuthFlows oauthFlows = new OAuthFlows();
auth.setFlows(oauthFlows);
@@ -410,25 +411,27 @@ public class RestOpenApiReader {
default:
throw new IllegalStateException("Invalid OAuth
flow '" + flow + "' specified");
}
- oauthFlow.setAuthorizationUrl(rs.getAuthorizationUrl());
- oauthFlow.setTokenUrl(rs.getTokenUrl());
- oauthFlow.setRefreshUrl(rs.getRefreshUrl());
+
oauthFlow.setAuthorizationUrl(CamelContextHelper.parseText(camelContext,
rs.getAuthorizationUrl()));
+
oauthFlow.setTokenUrl(CamelContextHelper.parseText(camelContext,
rs.getTokenUrl()));
+
oauthFlow.setRefreshUrl(CamelContextHelper.parseText(camelContext,
rs.getRefreshUrl()));
if (!rs.getScopes().isEmpty()) {
oauthFlow.setScopes(new Scopes());
for (RestPropertyDefinition scope : rs.getScopes()) {
- oauthFlow.getScopes().addString(scope.getKey(),
scope.getValue());
+
oauthFlow.getScopes().addString(CamelContextHelper.parseText(camelContext,
scope.getKey()),
+ CamelContextHelper.parseText(camelContext,
scope.getValue()));
}
}
- openApi.getComponents().addSecuritySchemes(def.getKey(),
auth);
+
openApi.getComponents().addSecuritySchemes(CamelContextHelper.parseText(camelContext,
def.getKey()), auth);
} else if (def instanceof MutualTLSDefinition) {
SecurityScheme auth = new
SecurityScheme().type(SecurityScheme.Type.MUTUALTLS)
- .description(def.getDescription());
- openApi.getComponents().addSecuritySchemes(def.getKey(),
auth);
+
.description(CamelContextHelper.parseText(camelContext, def.getDescription()));
+
openApi.getComponents().addSecuritySchemes(CamelContextHelper.parseText(camelContext,
def.getKey()), auth);
} else if (def instanceof OpenIdConnectDefinition) {
SecurityScheme auth = new
SecurityScheme().type(SecurityScheme.Type.OPENIDCONNECT)
- .description(def.getDescription());
- auth.setOpenIdConnectUrl(((OpenIdConnectDefinition)
def).getUrl());
- openApi.getComponents().addSecuritySchemes(def.getKey(),
auth);
+
.description(CamelContextHelper.parseText(camelContext, def.getDescription()));
+ auth.setOpenIdConnectUrl(
+ CamelContextHelper.parseText(camelContext,
((OpenIdConnectDefinition) def).getUrl()));
+
openApi.getComponents().addSecuritySchemes(CamelContextHelper.parseText(camelContext,
def.getKey()), auth);
}
}
}
@@ -1115,11 +1118,13 @@ public class RestOpenApiReader {
}
- private String inferOauthFlow(OAuth2Definition rs) {
+ private String inferOauthFlow(CamelContext camelContext, OAuth2Definition
rs) {
String flow;
- if (rs.getAuthorizationUrl() != null && rs.getTokenUrl() != null) {
+ if (CamelContextHelper.parseText(camelContext,
rs.getAuthorizationUrl()) != null
+ && CamelContextHelper.parseText(camelContext,
rs.getTokenUrl()) != null) {
flow = "authorizationCode";
- } else if (rs.getTokenUrl() == null && rs.getAuthorizationUrl() !=
null) {
+ } else if (CamelContextHelper.parseText(camelContext,
rs.getTokenUrl()) == null
+ && CamelContextHelper.parseText(camelContext,
rs.getAuthorizationUrl()) != null) {
flow = "implicit";
} else {
throw new IllegalStateException("Error inferring OAuth flow");
diff --git
a/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/SpringRestOpenApiReaderModelApiSecurityPlaceholderTest.java
b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/SpringRestOpenApiReaderModelApiSecurityPlaceholderTest.java
new file mode 100644
index 00000000000..c2a12f0938a
--- /dev/null
+++
b/components/camel-openapi-java/src/test/java/org/apache/camel/openapi/SpringRestOpenApiReaderModelApiSecurityPlaceholderTest.java
@@ -0,0 +1,145 @@
+/*
+ * 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.
+ */
+package org.apache.camel.openapi;
+
+import java.util.Map;
+
+import io.swagger.v3.oas.models.OpenAPI;
+import io.swagger.v3.oas.models.info.Info;
+import org.apache.camel.impl.engine.DefaultClassResolver;
+import org.apache.camel.test.spring.junit5.CamelSpringTestSupport;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.context.support.AbstractApplicationContext;
+import org.springframework.context.support.ClassPathXmlApplicationContext;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+public class SpringRestOpenApiReaderModelApiSecurityPlaceholderTest extends
CamelSpringTestSupport {
+
+ private Logger log = LoggerFactory.getLogger(getClass());
+
+ @Override
+ protected AbstractApplicationContext createApplicationContext() {
+ Map<String, Object> properties = Map.ofEntries(
+ Map.entry("oauth.key", "petstore_auth"),
+ Map.entry("oauth.description", "OAuth test"),
+ Map.entry("oauth.authorization.url",
"http://petstore.swagger.io/oauth/dialog"),
+ Map.entry("oauth.flow", "implicit"),
+ Map.entry("oauth.token.url",
"http://petstore.swagger.io/oauth/token"),
+ Map.entry("oauth.refresh.url",
"http://petstore.swagger.io/oauth/refresh"),
+ Map.entry("oauth.scopes", "read:pets,write:pets"),
+ Map.entry("oauth.scope.read", "read"),
+ Map.entry("oauth.scope.readers", "pets"),
+ Map.entry("oauth.scope.write", "write"),
+ Map.entry("oauth.scope.writers", "pets"),
+ Map.entry("apiKey.key", "api_key"),
+ Map.entry("apiKey.description", "API Key Test"),
+ Map.entry("apiKey.header.name", "myHeader"),
+ Map.entry("apiKey.inHeader", "true"),
+ Map.entry("apiKey.inCookie", "false"),
+ Map.entry("apiKey.inQuery", "false"),
+ Map.entry("bearer.key", "bearer"),
+ Map.entry("bearer.description", "Bearer Auth Test"),
+ Map.entry("bearer.format", "org.apache.camel.openapi.User"),
+ Map.entry("mtls.key", "mTLS"),
+ Map.entry("mtls.description", "mTLS Auth Test"),
+ Map.entry("oidc.key", "oidc"),
+ Map.entry("oidc.description", "OpenID Connect OAuth Test"),
+ Map.entry("oidc.url",
"http://petstore.swagger.io/oauth/.well-known/openid-configuration"),
+ Map.entry("basicAuth.key", "basic"),
+ Map.entry("basicAuth.description", "Basic Auth Test"));
+ System.getProperties().putAll(properties);
+ return new ClassPathXmlApplicationContext(
+
"org/apache/camel/openapi/SpringRestOpenApiReaderModelApiSecurityPlaceholderTest.xml");
+ }
+
+ @Test
+ public void testReaderReadV3() throws Exception {
+ BeanConfig config = new BeanConfig();
+ config.setHost("localhost:8080");
+ config.setSchemes(new String[] { "http" });
+ config.setBasePath("/api");
+ config.setTitle("Camel User store");
+ config.setLicense("Apache 2.0");
+
config.setLicenseUrl("http://www.apache.org/licenses/LICENSE-2.0.html");
+ config.setVersion(BeanConfig.OPENAPI_VERSION_31.getVersion()); //
Setting the version to 3.1 to test mTLS
+ Info info = new Info();
+ info.setDescription("OpenAPI 3.1 code first placeholder resolver test
for security definitions");
+ info.setVersion("1.0");
+ info.setTitle("OpenAPI Security Definitions Placeholder Resolver Test
1.0");
+ config.setInfo(info);
+ RestOpenApiReader reader = new RestOpenApiReader();
+
+ OpenAPI openApi = reader.read(context, context.getRestDefinitions(),
config, context.getName(),
+ new DefaultClassResolver());
+ assertNotNull(openApi);
+
+ String json = RestOpenApiSupport.getJsonFromOpenAPIAsString(openApi,
config);
+ log.info(json);
+
+ assertTrue(json.contains("\"securitySchemes\" : {"));
+ assertTrue(json.contains("\"type\" : \"oauth2\""));
+ assertTrue(json.contains("\"authorizationUrl\" :
\"http://petstore.swagger.io/oauth/dialog\""));
+ assertTrue(json.contains("\"tokenUrl\" :
\"http://petstore.swagger.io/oauth/token\""));
+ assertTrue(json.contains("\"refreshUrl\" :
\"http://petstore.swagger.io/oauth/refresh\""));
+ assertTrue(json.contains("\"flows\" : {"));
+ assertTrue(json.contains("\"implicit\" : {"));
+ assertTrue(json.contains("\"scopes\" : {"));
+ assertTrue(json.contains("\"read\" : \"pets\""));
+ assertTrue(json.contains("\"write\" : \"pets\""));
+ assertTrue(json.contains("\"type\" : \"apiKey\","));
+ assertTrue(json.contains("\"in\" : \"header\""));
+ assertTrue(json.contains("\"url\" : \"http://localhost:8080/api\""));
+ assertTrue(json.contains("\"security\" : [ {"));
+ assertTrue(json.contains("\"petstore_auth\" : [ \"write:pets\",
\"read:pets\" ]"));
+ assertTrue(json.contains("\"api_key\" : [ ]"));
+ assertTrue(json.contains("\"basic\" : [ ]"));
+ assertTrue(json.contains("\"bearer\" : [ ]"));
+ assertTrue(json.contains("\"oidc\" : [ ]"));
+ assertTrue(json.contains("\"mTLS\" : [ ]"));
+ assertTrue(json.contains("\"description\" : \"The user returned\""));
+ assertTrue(json.contains("\"$ref\" : \"#/components/schemas/User\""));
+ assertTrue(json.contains("\"format\" :
\"org.apache.camel.openapi.User\""));
+ assertTrue(json.contains("\"type\" : \"string\""));
+ assertTrue(json.contains("\"format\" : \"date\""));
+ assertTrue(json.contains("\"description\" : \"OAuth test\""));
+ assertTrue(json.contains("\"description\" : \"API Key Test\""));
+ assertTrue(json.contains("\"description\" : \"Basic Auth Test\""));
+ assertTrue(json.contains("\"description\" : \"Bearer Auth Test\""));
+ assertTrue(json.contains("\"description\" : \"OpenID Connect OAuth
Test\""));
+ assertTrue(json.contains("\"description\" : \"mTLS Auth Test\""));
+ assertTrue(json.contains("\"type\" : \"apiKey\""));
+ assertTrue(json.contains("\"type\" : \"http\""));
+ assertTrue(json.contains("\"type\" : \"mutualTLS\""));
+ assertTrue(json.contains("\"type\" : \"openIdConnect\""));
+ assertTrue(json.contains("\"name\" : \"myHeader\""));
+ assertTrue(json.contains("\"in\" : \"header\""));
+ assertTrue(json.contains("\"scheme\" : \"basic\""));
+ assertTrue(json.contains("\"scheme\" : \"bearer\""));
+ assertTrue(json.contains("\"bearerFormat\" :
\"org.apache.camel.openapi.User\""));
+ assertTrue(
+ json.contains("\"openIdConnectUrl\" :
\"http://petstore.swagger.io/oauth/.well-known/openid-configuration\""));
+ assertFalse(json.contains("\"enum\""));
+ assertFalse(json.contains("\"{{\""));
+
+ context.stop();
+ }
+}
diff --git
a/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/SpringRestOpenApiReaderModelApiSecurityPlaceholderTest.xml
b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/SpringRestOpenApiReaderModelApiSecurityPlaceholderTest.xml
new file mode 100644
index 00000000000..cbdbcb264c5
--- /dev/null
+++
b/components/camel-openapi-java/src/test/resources/org/apache/camel/openapi/SpringRestOpenApiReaderModelApiSecurityPlaceholderTest.xml
@@ -0,0 +1,93 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ 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.
+
+-->
+<beans xmlns="http://www.springframework.org/schema/beans"
+ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+ xsi:schemaLocation="
+ http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
+ http://camel.apache.org/schema/spring
http://camel.apache.org/schema/spring/camel-spring.xsd
+ ">
+
+ <!-- use a dummy rest consumer factory for the rest engine -->
+ <bean id="dummy-rest"
class="org.apache.camel.openapi.DummyRestConsumerFactory"/>
+
+ <bean id="userService" class="java.lang.Object"/>
+
+ <camelContext xmlns="http://camel.apache.org/schema/spring">
+
+ <rest path="/user" tag="dude" description="User rest service"
consumes="application/json" produces="application/json">
+ <securityDefinitions>
+ <oauth2 key="{{oauth.key}}"
authorizationUrl="{{oauth.authorization.url}}"
description="{{oauth.description}}"
+ tokenUrl="{{oauth.token.url}}" flow="{{oauth.flow}}"
refreshUrl="{{oauth.refresh.url}}">
+ <scopes key="{{oauth.scope.read}}"
+ value="{{oauth.scope.readers}}"/>
+ <scopes key="{{oauth.scope.write}}"
+ value="{{oauth.scope.writers}}"/>
+ </oauth2>
+ <apiKey key="{{apiKey.key}}" name="{{apiKey.header.name}}"
inHeader="{{apiKey.inHeader}}" description="{{apiKey.description}}"
+ inQuery="{{apiKey.inQuery}}" inCookie="{{apiKey.inCookie}}"/>
+ <basicAuth key="{{basicAuth.key}}"
description="{{basicAuth.description}}"/>
+ <bearer key="{{bearer.key}}" format="{{bearer.format}}"
description="{{bearer.description}}"/>
+ <mutualTLS key="{{mtls.key}}" description="{{mtls.description}}"/>
+ <openIdConnect key="{{oidc.key}}" url="{{oidc.url}}"
description="{{oidc.description}}"/>
+ </securityDefinitions>
+
+ <get path="/{id}/{date}" description="Find user by id and date"
outType="org.apache.camel.openapi.User">
+ <param name="id" type="path" description="The id of the user to get"/>
+ <param name="date" type="path" dataFormat="date" description="The
date"/>
+ <responseMessage message="The user returned"/>
+ <security key="{{apiKey.key}}"/>
+ <to uri="bean:userService?method=getUser(${header.id})"/>
+ </get>
+
+ <put description="Updates or create a user"
type="org.apache.camel.openapi.User">
+ <param name="body" type="body" description="The user to update or
create"/>
+ <security key="{{oauth.key}}"
scopes="write:{{oauth.scope.writers}},read:{{oauth.scope.readers}}"/>
+ <to uri="bean:userService?method=updateUser"/>
+ </put>
+
+ <get path="/findAll" description="Find all users"
outType="org.apache.camel.openapi.User[]">
+ <responseMessage message="All the found users"/>
+ <security key="{{basicAuth.key}}"/>
+ <to uri="bean:userService?method=listUsers"/>
+ </get>
+
+ <post path="/sendInfo" description="Send user information"
outType="java.lang.String">
+ <responseMessage message="User info sent"/>
+ <security key="{{oidc.key}}"/>
+ <to uri="bean:userService?method=listUsers"/>
+ </post>
+
+ <post path="/getInfo" description="get user information"
type="org.apache.camel.openapi.User" outType="java.lang.String">
+ <responseMessage message="User info found"/>
+ <security key="{{bearer.key}}"/>
+ <to uri="bean:userService?method=listUsers"/>
+ </post>
+
+ <get path="/test" description="Test the service"
outType="java.lang.String">
+ <responseMessage message="Tested the service successfully"/>
+ <security key="{{mtls.key}}"/>
+ <to uri="bean:userService?method=listUsers"/>
+ </get>
+
+ </rest>
+
+ </camelContext>
+
+</beans>