You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by da...@apache.org on 2024/09/07 06:12:46 UTC
(camel) branch camel-4.4.x updated: CAMEL-21164: camel-rest - Code first should use actual values for property placeholders in dumped API spec (#15460)
This is an automated email from the ASF dual-hosted git repository.
davsclaus pushed a commit to branch camel-4.4.x
in repository https://gitbox.apache.org/repos/asf/camel.git
The following commit(s) were added to refs/heads/camel-4.4.x by this push:
new 1b0beecfa8f CAMEL-21164: camel-rest - Code first should use actual values for property placeholders in dumped API spec (#15460)
1b0beecfa8f is described below
commit 1b0beecfa8f2301467f166bde11eec30a8c84be1
Author: avi5kdonrh <44...@users.noreply.github.com>
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 49753a4de42..c3deb0760e6 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
@@ -210,7 +210,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<>();
@@ -279,7 +279,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) {
@@ -296,36 +296,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);
@@ -348,25 +349,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);
}
}
}
@@ -1059,11 +1062,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>