diff --git a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpClientCodegen.java b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpClientCodegen.java index 75f3bc4c79eb..b8fbfafa6fcd 100644 --- a/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpClientCodegen.java +++ b/modules/openapi-generator/src/main/java/org/openapitools/codegen/languages/CSharpClientCodegen.java @@ -21,6 +21,7 @@ import io.swagger.v3.oas.models.Operation; import io.swagger.v3.oas.models.media.Schema; import io.swagger.v3.oas.models.servers.Server; +import io.swagger.v3.oas.models.security.SecurityRequirement; import lombok.Getter; import lombok.Setter; import org.openapitools.codegen.*; @@ -29,6 +30,7 @@ import org.openapitools.codegen.model.ModelsMap; import org.openapitools.codegen.utils.ModelUtils; import org.openapitools.codegen.utils.ProcessUtils; +import org.openapitools.codegen.model.OperationsMap; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -1026,9 +1028,68 @@ public CodegenOperation fromOperation(String path, SortParametersByRequiredFlag(op.allParams); } + if (GENERICHOST.equals(getLibrary())) { + addGenericHostSelectedSecurityRequirementNames(op, operation); + } + return op; } + private void addGenericHostSelectedSecurityRequirementNames(CodegenOperation op, Operation operation) { + List securityRequirements = operation.getSecurity() != null + ? operation.getSecurity() + : openAPI.getSecurity(); + + if (securityRequirements == null || securityRequirements.isEmpty()) { + return; + } + + SecurityRequirement selectedSecurityRequirement = securityRequirements.get(0); + + if (selectedSecurityRequirement == null || selectedSecurityRequirement.isEmpty()) { + op.vendorExtensions.put("x-csharp-generichost-selected-auth-names", Collections.emptySet()); + return; + } + + op.vendorExtensions.put("x-csharp-generichost-selected-auth-names", selectedSecurityRequirement.keySet()); + } + + private void filterGenericHostAuthMethodsForSelectedSecurityRequirement(CodegenOperation op) { + if (op.authMethods == null || op.authMethods.isEmpty()) { + return; + } + + Object selectedAuthNamesObject = op.vendorExtensions.get("x-csharp-generichost-selected-auth-names"); + + if (!(selectedAuthNamesObject instanceof Set)) { + return; + } + + Set selectedAuthNames = (Set) selectedAuthNamesObject; + + op.authMethods = op.authMethods.stream() + .filter(authMethod -> selectedAuthNames.contains(authMethod.name)) + .collect(Collectors.toList()); + + op.hasAuthMethods = !op.authMethods.isEmpty(); + } + + @Override + public OperationsMap postProcessOperationsWithModels(OperationsMap objs, List allModels) { + OperationsMap operationsMap = super.postProcessOperationsWithModels(objs, allModels); + + if (GENERICHOST.equals(getLibrary()) + && operationsMap != null + && operationsMap.getOperations() != null + && operationsMap.getOperations().getOperation() != null) { + for (CodegenOperation op : operationsMap.getOperations().getOperation()) { + filterGenericHostAuthMethodsForSelectedSecurityRequirement(op); + } + } + + return operationsMap; + } + public void addSupportingFiles(final String clientPackageDir, final String packageFolder, final AtomicReference excludeTests, final String testPackageFolder, final String testPackageName, final String modelPackageDir, final String authPackageDir) { final String library = getLibrary(); diff --git a/modules/openapi-generator/src/test/java/org/openapitools/codegen/csharpnetcore/CSharpClientCodegenTest.java b/modules/openapi-generator/src/test/java/org/openapitools/codegen/csharpnetcore/CSharpClientCodegenTest.java index a8c077a010e9..15fb1779869e 100644 --- a/modules/openapi-generator/src/test/java/org/openapitools/codegen/csharpnetcore/CSharpClientCodegenTest.java +++ b/modules/openapi-generator/src/test/java/org/openapitools/codegen/csharpnetcore/CSharpClientCodegenTest.java @@ -293,4 +293,36 @@ private List getNames(List props) { if (props == null) return null; return props.stream().map(v -> v.name).collect(Collectors.toList()); } + + @Test + public void testGenericHostUsesOnlyFirstSecurityRequirementForOrApiKeys() throws IOException { + File output = Files.createTempDirectory("test").toFile().getCanonicalFile(); + output.deleteOnExit(); + + final OpenAPI openAPI = TestUtils.parseFlattenSpec( + "src/test/resources/3_0/csharp/security-or-api-key.yaml"); + + final DefaultGenerator defaultGenerator = new DefaultGenerator(); + final ClientOptInput clientOptInput = new ClientOptInput(); + clientOptInput.openAPI(openAPI); + + CSharpClientCodegen cSharpClientCodegen = new CSharpClientCodegen(); + cSharpClientCodegen.setLibrary("generichost"); + cSharpClientCodegen.setOutputDir(output.getAbsolutePath()); + + clientOptInput.config(cSharpClientCodegen); + defaultGenerator.opts(clientOptInput); + + Map files = defaultGenerator.generate().stream() + .collect(Collectors.toMap(File::getPath, Function.identity())); + + File defaultApi = files.get(Paths.get(output.getAbsolutePath(), + "src", "Org.OpenAPITools", "Api", "DefaultApi.cs").toString()); + + assertNotNull(defaultApi); + assertFileContains(defaultApi.toPath(), "ApiKeyProvider.GetAsync(\"X-API-Key\""); + assertFileContains(defaultApi.toPath(), "UseInHeader(httpRequestMessageLocalVar)"); + assertFileNotContains(defaultApi.toPath(), "ApiKeyProvider.GetAsync(\"api-key\""); + assertFileNotContains(defaultApi.toPath(), "UseInQuery("); + } } diff --git a/modules/openapi-generator/src/test/resources/3_0/csharp/security-or-api-key.yaml b/modules/openapi-generator/src/test/resources/3_0/csharp/security-or-api-key.yaml new file mode 100644 index 000000000000..3d0fc8a9a44f --- /dev/null +++ b/modules/openapi-generator/src/test/resources/3_0/csharp/security-or-api-key.yaml @@ -0,0 +1,30 @@ +openapi: 3.0.3 +info: + title: Security OR Api Key Test + version: 1.0.0 + +servers: + - url: https://api.example.com + +security: + - apiKeyHeader: [] + - apiKeyQuery: [] + +paths: + /ping: + get: + operationId: ping + responses: + '200': + description: OK + +components: + securitySchemes: + apiKeyHeader: + type: apiKey + in: header + name: X-API-Key + apiKeyQuery: + type: apiKey + in: query + name: api-key \ No newline at end of file